首页 > 代码库 > hihoCoder挑战赛28 题目2 : 二进制翻转
hihoCoder挑战赛28 题目2 : 二进制翻转
题目2 : 二进制翻转
时间限制:20000ms
单点时限:1000ms
内存限制:256MB
描述
定义函数 Rev(x) 表示把 x 在二进制表示下翻转后的值
例如:
Rev(4)=1,因为 4 等于(100)B,翻转后是 (001)B,也就是 1
Rev(6)=3,因为 6 等于(110)B,翻转后是 (011)B,也就是 3
定义 Cnt(x) 表示 x 在二进制表示下 1 的个数,求:
输入
仅一行,一个非负整数 n
0 ≤ n ≤ 1015
输出
仅一行:一个非负整数表示答案
- 样例输入
2
- 样例输出
3
/* Name: rev x& count num 1 of x in binary Copyright: @2017 shenben Author: shenben Date: 25/04/17 16:47 Description://枚举当前要计算的数的位数,考虑从左右往中间dp//f[i][j][k][cmp1][cmp2]表示考虑了前 i 位和后 i 位,前 i 位需要 j 个进位,后 i 位的进位为 k,前 i 位和后 i 位和上限的大小情况分别是 cmp1,cmp2//转移时,同时枚举第 i+1 位和倒数第 i+1 位的值,枚举该位最后是否是 1 ,根据这个判断是否需要进位即可//时间复杂度 O((logn)^2)//(来自官方题解) */#include<cstdio>#include<cstring>#include<cstdlib>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int N=55;ll n,ans;int m,dig[N];ll f[N][N][2][3][2];ll s[N][N][2][3][2];inline int fun(int b,int x,int y){ if(x==y) return b; if(x<y) return 2; return 0;}void solve(){ memset(f,0,sizeof f); memset(s,0,sizeof s); if(m==1){ans++;return ;} f[1][1][0][fun(1,0,dig[1])][0]=1; f[1][0][0][fun(1,1,dig[1])][1]=1; s[1][1][0][fun(1,0,dig[1])][0]=2; s[1][0][0][fun(1,1,dig[1])][1]=2; for(int i=2;i<=m/2;i++){ for(int j=0;j<=m;j++){ for(int a=0;a<2;a++){ for(int b=0;b<3;b++){ for(int c=0;c<2;c++){ ll k=f[i-1][j][a][b][c]; ll l=s[i-1][j][a][b][c]; if(!k) continue; //0,0 f[i][0][a|(dig[m-i+1]==1)][fun(b,0,dig[i])][0]+=k; s[i][0][a|(dig[m-i+1]==1)][fun(b,0,dig[i])][0]+=l; //0,1 f[i][j+1][a|(dig[m-i+1]==1)][fun(b,1,dig[i])][c]+=k; s[i][j+1][a|(dig[m-i+1]==1)][fun(b,1,dig[i])][c]+=l+k*(2-c); if(a|(dig[m-i+1]==1)){ //1,0 f[i][j+1][a][fun(b,0,dig[i])][c]+=k; s[i][j+1][a][fun(b,0,dig[i])][c]+=l+k*(2-c); //1,1 f[i][0][a][fun(b,1,dig[i])][1]+=k; s[i][0][a][fun(b,1,dig[i])][1]+=l+k*(2-j); } } } } } } if(m&1){ int i=m+1>>1; for(int j=0;j<=m;j++){ for(int a=0;a<2;a++){ for(int b=0;b<3;b++){ for(int c=0;c<2;c++){ ll k=f[i-1][j][a][b][c]; ll l=s[i-1][j][a][b][c]; if(!k) continue; //0 f[i][0][a|(dig[m-i+1]==1)][b][0]+=k; s[i][0][a|(dig[m-i+1]==1)][b][0]+=l; //1 if(a|(dig[m-i+1]==1)){ f[i][0][a][b][0]+=k; s[i][0][a][b][0]+=l+k*(1-j); } } } } } } int i=m+1>>1; for(int j=0;j<=m;j++){ for(int a=0;a<2;a++){ for(int b=0;b<3;b++){ for(int c=0;c<2;c++){ if(!a&&!b) continue; ll k=f[i][j][a][b][c]; ll l=s[i][j][a][b][c]; if(!k) continue; ans+=l; if(c) ans-=k*j; } } } } }int main(){ cin>>n; for(ll t=n;t;t>>=1) dig[++m]=t&1; for(solve();--m;){ for(int i=1;i<=m;i++) dig[i]=1; solve(); } cout<<ans; return 0;}
hihoCoder挑战赛28 题目2 : 二进制翻转
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。