luogu 3702 [SDOI2017]序列计数 矩阵乘法+容斥

现在看来这道题真的不难啊~

正着求不好求,那就反着求:答案=总-全不是质数 

这里有一个细节要特判:1不是质数,所以在算全不是质数的时候要特判1 

code: 

#include <bits/stdc++.h>           
#define N 104 
#define M 20000002 
#define mod 20170408    
#define ll long long  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;  
int n,m,p,tot; 
int cnt[N];
bool vis[M];
int prime[200000],cnt2[N];  
struct matrix 
{   
    ll a[100][100];               
    void re() { memset(a,0,sizeof(a));}  
    void I() { re(); for(int i=0;i<p;++i) a[i][i]=1ll;  }
    ll*operator[](int x) { return a[x]; }                       
}A,B;   
matrix operator*(matrix a,matrix b) 
{    
    matrix c;c.re();           
    int i,j,k; 
    for(i=0;i<p;++i) 
    {
        for(j=0;j<p;++j)
            for(k=0;k<p;++k) 
                c[i][j]=(c[i][j]+a[i][k]*b[k][j]%mod+mod)%mod;   
    }   
    return c;      
}
matrix operator^(matrix a,ll k) 
{   
    matrix tmp;                    
    for(tmp.I();k;k>>=1,a=a*a) if(k&1) tmp=tmp*a;   
    return tmp;      
}
int main() 
{ 
    // setIO("input");           
    int i,j; 
    scanf("%d%d%d",&n,&m,&p);        
    for(i=1;i<=m;++i) cnt[i%p]++;        
    for(i=2;i<=m;++i) 
    {   
        if(!vis[i]) prime[++tot]=i;  
        for(j=1;j<=tot&&prime[j]*i<=m;++j) 
        {
            vis[i*prime[j]]=1;  
            if(i%prime[j]==0) break;       
        }         
    }    
    for(i=1;i<=m;++i) if(vis[i]) ++cnt2[i%p]; 
    ++cnt2[1%p];                            
    A.re();          
    B.re();    
    for(i=0;i<p;++i) 
    {
        for(j=0;j<p;++j) 
        {
            int pp=(j-i+p)%p;        
            A[i][j]=cnt[pp];                            
            B[i][j]=cnt2[pp];                                 
        }
    }                      
    A=A^n;       
    B=B^n;          
    // printf("%lld %lld\n",A[0][0],B[0][0]);   
    printf("%lld\n",(A[0][0]-B[0][0]+mod)%mod);        
    return 0;
}

  

posted @ 2019-10-12 18:55  EM-LGH  阅读(121)  评论(0编辑  收藏  举报