1. 程式人生 > >hdu 2197 本原串(容斥定理)

hdu 2197 本原串(容斥定理)

本原串

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


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
Author scnu

題解:假設f【i】代表本源串個數,則本源串f【n】=  pow(2,n)-sigma(f【i】)-2,其中i | n 且 i>=2 ,

因為當 i 為 n 的約數時候,就可以重疊所有長度為 i 的本源串均可變成長度為 n 的非本源串,最後減去2是長度為1的時候重疊出的2種情況

#include<stdio.h>
#include<map>
#define mod 2008
using namespace std;
map<int,int>mip;
int fast_pow(int a,int b)
{
    int res=1;

    while(b)
    {
        if(b&1) res=(res*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }

    return res;
}
int cal(int x)
{
    int ans=(fast_pow(2,x)-2)%mod,i;

    if(mip[x]) return mip[x];
    if(x==1) return mip[x]=2;
    for(i=2;i*i<=x;i++)
    {
        if(x%i!=0) continue;
        if(i*i==x)
        {
            ans=(ans-cal(i))%mod;
        }
        else
        {
            ans=(ans-cal(i))%mod;
            ans=(ans-cal(x/i))%mod;
        }
    }

    return mip[x]=(ans+mod)%mod;
}
int main()
{
    int x;

    while(scanf("%d",&x)>0)
    {
        printf("%d\n",cal(x));
    }
}