显然数位DP。
dp[i][j]表示所有末尾为j的i位二进制数相邻位的数量和
初始状态dp[2][1]=1
从长度i-1转移到长度i就是在i-1位的末尾添上0或1,转移方程就是:
dp[i][0]=dp[i-1][0]+dp[i-1][1]
dp[i][1]=dp[i-1][0]+dp[i-1][1]+2i-2
预处理完后,就可以通过这个计算出[0,n]区间的数量和,还是感觉数位DP的这一步挺棘手的,具体问题具体分析吧。。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 long long d[32][2]; 5 int main(){ 6 d[2][1]=1; 7 for(int i=3; i<32; ++i){ 8 d[i][0]=d[i-1][0]+d[i-1][1]; 9 d[i][1]=d[i-1][0]+d[i-1][1]+(1<<i-2); 10 } 11 int t; 12 long long n; 13 scanf("%d",&t); 14 for(int cse=1; cse<=t; ++cse){ 15 scanf("%lld",&n); 16 long long res=0; 17 for(int i=30; i>=0; --i){ 18 if((n>>i)&1) res+=d[i][0]+d[i][1]; 19 if(((n>>i)&1) && ((n>>i+1)&1)) res+=(n&((1LL<<i+2)-1))-((1<<i)|(1<<i+1))+1; 20 } 21 printf("Case %d: %lld\n",cse,res); 22 } 23 return 0; 24 }
时间: 2024-10-25 15:06:48