HDU 2197 - 本原串(递推规律)

本原串

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;
}

猜你喜欢

转载自blog.csdn.net/l18339702017/article/details/81711381