本原串(HDU 2197 快速幂)

本原串

Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1091    Accepted Submission(s): 350


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
 
F[n]=2^n-F[k],k为n的约数。
此题用反面情况求解,长度为n的串有2^n中,减去非本原串,非本原串肯定是由长度为v字串不断重复u次得到的,那么v必然是n的约数。
感觉很长时间没做题了脑袋笨了不少,约数枚举法忘了。不然肯定超时
 1 #include <cstring>
 2 #include <iostream>
 3 #include <cstdio>
 4 #include <algorithm>
 5 #include <map>
 6 using namespace std;
 7 typedef long long LL;
 8 map<int,int> m;
 9 map<int,int>::iterator ite;
10 LL n,ans;
11 LL mod_pow(LL x,LL n,int mod)
12 {
13     LL res=1;
14     while(n)
15     {
16         if(n&1)
17             res=res*x%mod;
18         x=x*x%mod;
19         n>>=1;
20     }
21     return res;
22 }
23 int cal(LL n)
24 {
25     int i,j;
26     if(m[n]!=0)
27         return m[n];
28     m[n]=mod_pow(2,n,2008)-2;
29     for(i=2;i*i<=n;i++)
30     {
31         if(n%i==0)
32         {
33             m[n]=(m[n]-cal(i)+2008)%2008;    //不然可能是负数
34             if(i*i!=n)
35                 m[n]=(m[n]-cal(n/i)+2008)%2008;
36 
37         }
38     }
39     return m[n];
40 }
41 int main()
42 {
43     m[0]=0;
44     m[1]=2;
45     m[2]=2;
46     //freopen("in.txt","r",stdin);
47     while(scanf("%d",&n)!=EOF)
48     {
49         if(n<=2)
50             printf("%d
",m[n]);
51         else
52         {
53             m[n]=cal(n);
54             printf("%d
",m[n]);
55         }
56     }
57 }
 
原文地址:https://www.cnblogs.com/a1225234/p/5462132.html