本原串
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 408 Accepted Submission(s): 129
Problem Description
由0和1组成的串中,不能表示为由几个相同的较小的串连接成的串,称为本原串,有多少个长为n(n<=100000000)的本原串?
答案mod2008.
例如,100100不是本原串,因为他是由两个100组成,而1101是本原串。
答案mod2008.
例如,100100不是本原串,因为他是由两个100组成,而1101是本原串。
Input
输入包括多个数据,每个数据一行,包括一个整数n,代表串的长度。
Output
对于每个测试数据,输出一行,代表有多少个符合要求本原串,答案mod2008.
Sample Input
1
2
3
4
Sample Output
2
2
6
12
Author
scnu
Recommend
lcy
本题比较有意思的题目。
长度为n的01串的总数为2^n.要求本原串,只要总数减掉非本原串。
非本原串可以由本原串得到。
f[n]=2^n - 求和(f[i]) -2 其中i是n的大于等于2的约数。
找约数的时候,只要2到sqrt(n)枚举。因为找到一个i,那么n/i一定是约数了。
具体看代码吧。
/* * G++ 0ms 336K */ #include <stdio.h> #include <algorithm> #include <iostream> #include <iostream> #include <string> #include <map> using namespace std; const int MOD=2008; map<int,int>mp; int pow_m(int a,int n) { int ret=1; int tmp=a%MOD; while(n) { if(n&1) { ret*=tmp; ret%=MOD; } tmp*=tmp; tmp%=MOD; n>>=1; } return ret; } int get(int x) { if(mp[x]!=0)return mp[x]; if(x==1)return mp[x]=2; int ans=pow_m(2,x); ans-=2; ans%=MOD; for(int i=2;i*i<=x;i++) { if(x%i!=0)continue; if(i*i==x) { ans-=get(i); ans%=MOD; } else { ans-=get(i); ans-=get(x/i); ans%=MOD; } } return mp[x]=(ans+MOD)%MOD; } int main() { int n; while(scanf("%d",&n)==1) { printf("%d\n",get(n)); } return 0; }
代码二:
/* *G++ 15ms 360K */ #include <stdio.h> #include <algorithm> #include <iostream> #include <iostream> #include <string.h> #include <map> using namespace std; const int MOD=2008; int a[10010]; int pow_m(int a,int n) { int ret=1; int tmp=a%MOD; while(n) { if(n&1) { ret*=tmp; ret%=MOD; } tmp*=tmp; tmp%=MOD; n>>=1; } return ret; } int get(int x) { if(x<=10000&&a[x]!=0)return a[x]; if(x==1)return 2; int ans=pow_m(2,x); ans-=2; ans%=MOD; for(int i=2;i*i<=x;i++) { if(x%i!=0)continue; if(i*i==x) { ans-=get(i); ans%=MOD; } else { ans-=get(i); ans-=get(x/i); ans%=MOD; } } return (ans+MOD)%MOD; } int main() { int n; memset(a,0,sizeof(a)); for(int i=1;i<=10000;i++)a[i]=get(i); while(scanf("%d",&n)==1) { printf("%d\n",get(n)); } return 0; }