bzoj4818【SDOI2017】序列计数 矩阵快速幂+动态规划

来源:互联网 发布:淘宝店铺如何更换行业 编辑:程序博客网 时间:2024/05/29 03:09

讲道理,最后一道题目不应该是防AK题么,为啥这么水。。
首先一眼容斥,用总方案-不含有质数的方案。
设f[i][j]表示前i个数的和对p的取模为j,明显有f[i][j]=sigma(f[i-1][(j-k)%p]);
然后建构矩阵直接快速幂即可。

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#define fo(i,a,b) for(int i=a;i<=b;i++)using namespace std;typedef long long ll;const int M=3e7+5;const int N=2e6+5;const int mo=20170408;int n,m,p;int pr[N],tot,f[205];bool vis[M];struct node{    int mat[105][105];}ans,a;inline void mul(node &c,node a,node b){    memset(c.mat,0,sizeof(c.mat));    fo(i,0,p-1)    fo(j,0,p-1)    fo(k,0,p-1)    c.mat[i][j]=(c.mat[i][j]+1ll*a.mat[i][k]*b.mat[k][j]%mo)%mo;}inline node pow(node a,int b){    memset(ans.mat,0,sizeof(ans.mat));    fo(i,0,p-1) ans.mat[i][i]=1;    while (b)    {        if (b&1) mul(ans,ans,a);        mul(a,a,a);        b>>=1;    }    return ans;}inline int solve1(){    fo(i,1,m) f[i%p]++;    fo(j,1,m) a.mat[(-j%p+p)%p][0]++;    fo(i,1,p-1)    fo(j,0,p-1)            a.mat[j][i]=a.mat[(j-1+p)%p][i-1];    a=pow(a,n-1);    int ans=0;    fo(i,0,p-1)     ans=(ans+1ll*f[i]*a.mat[i][0]%mo)%mo;    return ans;}inline int solve2(){    memset(f,0,sizeof(f));    fo(i,1,m)    if (vis[i]) f[i%p]++;    memset(a.mat,0,sizeof(a.mat));    fo(j,1,m)    if (vis[j]) a.mat[(-j%p+p)%p][0]++;    fo(i,1,p-1)    fo(j,0,p-1)    a.mat[j][i]=a.mat[(j-1+p)%p][i-1];    a=pow(a,n-1);    int ans=0;    fo(i,0,p-1)      ans=(ans+1ll*f[i]*a.mat[i][0]%mo)%mo;    return ans;}int main(){    freopen("count.in","r",stdin);    freopen("count.out","w",stdout);    scanf("%d%d%d",&n,&m,&p);    vis[1]=1;    fo(i,2,m)    {        if (!vis[i]) pr[++tot]=i;        fo(j,1,tot)        {            if (i*pr[j]>m)break;            vis[i*pr[j]]=1;            if (i%pr[j]==0) break;        }    }    int ans1=solve1();    int ans2=solve2();    printf("%d",(ans1-ans2+mo)%mo);    return 0;}
0 0
原创粉丝点击