ZOJ 3707 Calculate Prime S 数论

思路:容易得到s[n]=s[n-1]+s[n-2],也就是fib数。

求第k小的fib质数的也就是第k个质数数-2,当k>2时。

在就是s[n]/x%m=s[n]%(x*m)/x.

代码如下:

 

#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
#define M 1000005
using namespace std;
ll k,x,m;
int prime[M],cnt;
bool f[20*M];
struct mat
{
    ll m[2][2];
};
mat mul(mat a,mat b,ll mod)
{
    mat ans;
    for(int i=0;i<2;i++)
    for(int j=0;j<2;j++){
        ans.m[i][j]=0;
        for(int z=0;z<2;z++)
            ans.m[i][j]=(ans.m[i][j]+a.m[i][z]*b.m[z][j])%mod;
    }
    return ans;
}
ll pw(ll n,ll mod)
{
    mat ans,a;
    for(int i=0;i<2;i++)
    for(int j=0;j<2;j++){
        ans.m[i][j]=0;
        a.m[i][j]=1;
    }
    ans.m[0][0]=2;ans.m[0][1]=1;a.m[1][1]=0;
    while(n){
        if(n&1) ans=mul(ans,a,mod);
        n>>=1;
        a=mul(a,a,mod);
    }
    ll aa=ans.m[0][1];
    ll bb=ans.m[0][0];
    while(1){
        if(bb%x==0) break;
        ll t=(aa+bb)%mod;
        aa=bb;
        bb=t;
    }
    return bb;
}
void init()
{
    cnt=1;
    for(int i=2;i<20*M;i++){
        if(cnt>=1000001) break;
        if(!f[i]) prime[cnt++]=i;
        for(int j=1;j<cnt&&i*prime[j]<20*M;j++){
            f[i*prime[j]]=1;
            if(i%prime[j]==0) break;
        }
    }
}
ll gcd(ll a,ll b)
{
    if(a<b) swap(a,b);
    while(b){
        ll t=a;
        a=b;
        b=t%b;
    }
    return a;
}
ll cal(ll mod)
{
    ll a=2,b=3,c;
    if(k==1) c=2;
    else c=3;
    while(1){
        if(a>=c&&a%x==0) break;
        ll t=(a+b)%mod;
        a=b;
        b=t;
    }
    return a;
}
int main()
{
    int t;
    init();
    scanf("%d",&t);
    while(t--){
        scanf("%lld%lld%lld",&k,&x,&m);
        ll ans,g=x*m;
        if(k<=2) ans=cal(g);
        else ans=pw(prime[k]-2,g);
        printf("%lld\n",ans/x);
    }
    return 0;
}
View Code

 

 

 

posted @ 2013-10-31 21:10  _随心所欲_  阅读(493)  评论(0编辑  收藏  举报