1. 程式人生 > >HDU 2197 本原串 快速冪取模+遞推

HDU 2197 本原串 快速冪取模+遞推

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的由0,1組成的字串一共有2^n個.
所以只要求出不是本元串的個數就可以了...
一開始以為此題只與素因子有關,但是想到8的時候發現並不是...
百度了一波題解,發現原來有遞推關係....
遞推關係為:
len[n]=2^n-len[x]. 
x為n的因子.... 
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <map>
using namespace std;
int n;
map<int,int>ma;
int fastpow (int a,int b)
{
    int sum=1;
    while (b>0)
    {
        if(b&1)
           sum=sum*a%2008;
        b>>=1;
        a=a*a%2008;
    }
    return sum;
}
int Div (int x)
{
    if(x==1)
        return 2;
    if(ma.find(x)!=ma.end())
         return ma[x];
    int sum=fastpow(2,x);
    for (int i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
           sum=(sum-Div(i)+2008)%2008;
           if(i*i!=x)
                sum=(sum-Div(x/i)+2008)%2008;
        }
    }
    return ma[x]=(sum+2006)%2008;
}
int main()
{
    while (scanf("%d",&n)!=EOF)
    {
       printf("%d\n",Div(n));
    }
    return 0;
}