本原串
Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1709 Accepted Submission(s): 589
Problem Description
由0和1组成的串中,不能表示为由几个相同的较小的串连接成的串,称为本原串,有多少个长为n(n<=100000000)的本原串?
答案mod2008.
例如,100100不是本原串,因为他是由两个100组成,而1101是本原串。
Input
输入包括多个数据,每个数据一行,包括一个整数n,代表串的长度。
Output
对于每个测试数据,输出一行,代表有多少个符合要求本原串,答案mod2008.
Sample Input
1
2
3
4
Sample Output
2
2
6
12
写在最前:也不是在下不谦虚,要是不看题解,这辈子我也看不出来这个规律。
思路:
对于这道题,方法很好理解,就是长度为n的本原串可以由从2开始的n的约数的本原串计算,计算式如下:F[n]=2^n - ΣF[i] - 2;(其中,i是n的约数)。
可以这么理解:长度n的串共有2^n,F[n]=2^n-非本原串;非本原串=长度是n的约数的本原串的个数+2(加2的原因是因为本原串没有全0和全1的情况,非本原串要加上)
长度是n的非本原串个数=ΣF[i](其中,i是n的约数,即可以由长度是i的子串构成长度是n的非本原串)
#include <bits/stdc++.h>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
#define line cout<<"---------------------"<<endl;
typedef long long ll;
const int maxn = 1e5+10;
const int inf = 0x3f3f3f3f;
const int Mod = 2008;
const int N = 100000005;
ll n;
ll f[N];
ll pow_mod(ll a,ll n){
ll ans=1;
while(n){
if(n & 1)
ans = ans * a % Mod;
a = a * a % Mod;
n>>=1;
}
return ans % Mod;
}
ll get_num(ll n){
if(f[n]) return f[n];
if(n == 1) return 2;
int ans = pow_mod(2,n);
for(int i=2;i*i<=n;i++){
if(n % i == 0){//找到一个约数
ans = (ans - get_num(i) ) % Mod;
int t = n/i;
if(i * i != n)//找到对应的另一个约数
ans = (ans - get_num(t) + Mod) % Mod;
}
}
return f[n] = (ans - 2 +Mod) % Mod;
}
int main(){
while(scanf("%lld",&n)!=EOF){
printf("%lld\n",get_num(n) );
}
return 0;
}