Input
输入包括多个数据,每个数据一行,包括一个整数n,代表串的长度。
Output
对于每个测试数据,输出一行,代表有多少个符合要求本原串,答案mod2008.
Sample Input
1
2
3
4
Sample Output
2
2
6
12
题意说的是有一个长度为n的01串。每个位置都可以为0或者为1。问这个长度为n的串可以由0和1组成没有循环节的串 有多少种方案。
思路:
每个位置都可以为0或者为1,所以一共有
种方案组成这个串,由于这个串不能有循环节,我们可以反向考虑有循环节的时候。有循环节的话,假设循环节长度为
,则必然有
,即找到n的因子,每个因子代表一个循环节的长度,比如当
的时候,它的因子为
,那么长度为1的串可能有
种,长度为2的串可能有
种,长度为4的串可能有
种。
依据加法定理,把这些相加就包含了所有情况,但是!!!这里面显然有重复的啊!比如长度为1的串为1,长度为2 的串为11,显然11111111这个串被重复构造,显然长度为2的循环节不能再分成长度为1 的循环节才符合我们想要的要求,即不能有11这样的长度为2的循环节。那可能么办?
我忍不住要问一句,您真的明白题目中本原串的定义吗?
本原串的定义是长度为
的串没有循环节,而我们要的上述长度为k的循环节也是不能有循环节的,不然就会有重复。所以长度为
的循环节显然就是长度为
的本源串。
综上,我们可以递归的去寻找原串,在过程中避免重复寻找,把求过的本源串记下来就行了。
#include<iostream>
#include<cstring>
#include<queue>
#include<map>
#include<cmath>
#include<set>
#include<stack>
#include<cstdio>
#include<sstream>
#include<vector>
#include<bitset>
#include<algorithm>
#include<unordered_map>
using namespace std;
#define read(x) scanf("%d",&x)
#define Read(x,y) scanf("%d%d",&x,&y)
#define gc(x) scanf(" %c",&x);
#define mmt(x,y) memset(x,y,sizeof x)
#define write(x) printf("%d\n",x)
#define pii pair<int,int>
#define INF 0x3f3f3f3f
#define ll long long
const int N = 100000 + 100;
const int M = 3e6 + 1005;
typedef long long LL;
unordered_map<int,ll> hap;//记录求过的本源串
ll Qpow(ll a,ll b,ll p){
ll ans = 1;
a %= p;
while(b){
if(b&1) ans = ans * a%p;
b >>= 1;
a = a*a%p;
}
return ans;
}
ll solve(ll n){
ll sum = 0;
for(int i = 1;i <= sqrt(n);++i){
if(n % i == 0){
if(i == 1) sum = (sum + 2)%2008;
else {
if(hap.count(i)) sum = (sum + hap[i]) % 2008;
else {
hap[i] = solve(i);
sum = (sum + hap[i]) % 2008;
}
if(i == n/i) continue;
if(hap.count(n/i)) sum = (sum + hap[n/i])% 2008;
else{
hap[n/i] = solve(n/i);
sum = (sum + hap[n/i]) % 2008;
}
}
}
}
return (Qpow(2,n,2008) - sum + 2008)%2008;
}
int main(){
int n;
hap[1] = 2;
hap[2] = 2;
hap[3] = 6;
while(scanf("%d",&n) == 1){
if(hap.count(n)) printf("%lld\n",hap[n]);
else {
hap[n] = solve(n) ;
printf("%lld\n",hap[n]);
}
}
}