連結:http://www.codeforces.com/problemset/problem/215/E
題意:問你 l r之間有多少的數是周期數,周期數的定義為:這個數的二進位形式是以k為周期的,k<n;假設二進位長為n
l r 很大很大- -
其實就是一般的按位統計的方法,在求長度小於len的二進位中有多少的位元是周期數時,可以枚舉周期為1 2 3 。。。,當然這個周期都是獨一無二的,比如當前枚舉周期為6,那周期為2 和 3 的也會被算進來,所以要減去周期為2 和 3的總數,保證沒有重複
然後就是統計的過程了,我是先統計位元比要求的數小的,然後再統計位元相同的,也還是老套路,如果當前數位為1,就可以把它變成0,然後後面的數位都可以隨便取
最後別忘了當前枚舉的周期,這個數本身是否滿足
比如101 111 111
當我枚舉3為周期的時候,別忘了判斷 101 101 101是否小於要求的數,如果是,還要加個1
具體見代碼吧,應該很好懂
#include<cstdio>#include<cstring>#include<queue>#include<vector>#include<algorithm>using namespace std;typedef __int64 lld;lld POW[70];lld dp[70];lld calc(int n){ lld ans=0; for(int i=1;i<n;i++)if(n%i==0) { dp[i]=POW[i-1];//dp[1]=POW[0]=1 to avoid trailing zreos for(int j=1;j<i;j++) if(i%j==0) dp[i]-=dp[j]; ans+=dp[i]; } return ans;}lld gao(lld num){ vector<int> DBL; lld ans=0,cnt=0,tmp=num; for(;tmp;tmp/=2) DBL.push_back(tmp%2); reverse(DBL.begin(),DBL.end()); for(int i=1;i<DBL.size();i++) ans+=calc(i);// printf("ans=%I64d\n",ans); for(int i=1;i<DBL.size();i++) if(DBL.size()%i==0) { //printf("i=%d \n",i); lld sum=DBL[0]; dp[i]=0; for(int j=2;j<=i;j++) { if(DBL[j-1]) dp[i]+=POW[i-j]; sum=sum*2+DBL[j-1]; } lld tmp=sum; for(int j=1;j<DBL.size()/i;j++) sum=sum*POW[i]+tmp; //printf("sum=%I64d\n",sum); dp[i]+=(sum<=num); for(int j=1;j<i;j++) if(i%j==0) dp[i]-=dp[j]; ans+=dp[i]; } return ans;}int main(){ lld l,r; POW[0]=1; for(int i=1;i<70;i++) POW[i]=POW[i-1]*2; scanf("%I64d%I64d",&l,&r); printf("%I64d\n",gao(r)-gao(l-1)); return 0;}