codevs 5964 [SDOI2017]序列计数

Posted 神犇(shenben)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了codevs 5964 [SDOI2017]序列计数相关的知识,希望对你有一定的参考价值。

 [题解]

官方题解就两句话。

 

写了三个版本的不同分值代码。看代码吧。

前导1

//f[i][j][1/0]表示长为i,sum mod p=j,是否已经选了质数的方案数
#include<cstdio>
using namespace std;
const int mod=20170408;
const int N=1e6+1;
int tot,prime[N/3];bool check[N];
int n,m,f[2][N][2];int p;
void pre(){
    n=1e6;check[0]=check[1]=1;
    for(int i=2;i<=n;i++){
        if(!check[i]) prime[++tot]=i;
        for(int j=1;j<=tot&&i*prime[j]<=n;j++){
            check[i*prime[j]]=1;
            if(!(i%prime[j])) break;
        } 
    }
}
int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    pre();
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=m;i++) f[1][i%p][!check[i]]++;
    for(int i=1,val;i<n;i++){
        for(int j=0;j<p;j++){
            for(int k=1;k<=m;k++){
                val=(j+k)%p;
                if(!check[k]){
                    f[i+1&1][val][1]=(f[i+1&1][val][1]+f[i&1][j][0]+f[i&1][j][1])%mod;
                }
                else{
                    f[i+1&1][val][0]=(f[i+1&1][val][0]+f[i&1][j][0])%mod,
                    f[i+1&1][val][1]=(f[i+1&1][val][1]+f[i&1][j][1])%mod;
                }
            }
        }
        for(int j=0;j<p;j++){
            f[i&1][j][0]=0;
            f[i&1][j][1]=0;
        }
    }
    printf("%d",f[n&1][0][1]);
    return 0;
}

前导2

#include<cstdio>
using namespace std;
const int mod=20170408;
const int N=1e6+1;
int tot,prime[N/3];bool check[N];
int n,m,p;
int f[2][N];
int g[2][N];
int sz[N];
void pre(){
    n=1e6;check[0]=check[1]=1;
    for(int i=2;i<=n;i++){
        if(!check[i]) prime[++tot]=i;
        for(int j=1;j<=tot&&i*prime[j]<=n;j++){
            check[i*prime[j]]=1;
            if(!(i%prime[j])) break;
        } 
    }
}
int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    pre();
    scanf("%d%d%d",&n,&m,&p);
    //全集 
    for(int k=1;k<=p;k++) sz[k]=m/p+(m%p>=k);sz[0]=sz[p];
    for(int i=0;i<p;i++) f[1][i]=sz[i];
    for(int i=1,val;i<n;i++){
        for(int j=0;j<p;j++){
            for(int k=0;k<p;k++){
                val=(j+k)%p;
                f[i+1&1][val]=(f[i+1&1][val]+sz[k]*f[i&1][j])%mod;
            }
        }
        for(int j=0;j<p;j++) f[i&1][j]=0;
    }
    //不包含素数 
    for(int i=1;i<=tot&&prime[i]<=m;i++) sz[prime[i]%p]--;
    for(int i=0;i<p;i++) g[1][i]=sz[i];
    for(int i=1,val;i<n;i++){
        for(int j=0;j<p;j++){
            for(int k=0;k<p;k++){
                val=(j+k)%p;
                g[i+1&1][val]=(g[i+1&1][val]+sz[k]*g[i&1][j])%mod;
            }
        }
        for(int j=0;j<p;j++) g[i&1][j]=0;
    }
    printf("%d",f[n&1][0]-g[n&1][0]);
    return 0;
}

AC代码

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int mod=20170408;
const int N=101;
const int M=2e7+5;
int tot,prime[M/3];bool check[M];
int n,m,p;
int sz[N];
struct matrix{
    ll s[N];//降低常数 
    matrix(){
        memset(s,0,sizeof s);
    }
}A,B;
matrix operator *(const matrix &a,const matrix &b){
    matrix c;
    for(int i=0;i<p;i++){
//        c.s[i]=0;
        for(int k=0;k<p;k++){
            c.s[i]+=a.s[(i-k+p)%p]*b.s[k];
            c.s[i]%=mod;
        } 
    }
    return c;
}
ll fpow(matrix a,ll p){
    matrix res;
//    for(int i=0;i<p;i++) res.s[i]=0;
    res.s[0]=1;
    for(;p;p>>=1,a=a*a) if(p&1) res=res*a;
    return res.s[0];
}
void pre(){
    check[0]=check[1]=1;
    for(int i=2;i<=m;i++){
        if(!check[i]) prime[++tot]=i;
        for(int j=1;j<=tot&&i*prime[j]<=m;j++){
            check[i*prime[j]]=1;
            if(!(i%prime[j])) break;
        } 
    }
}
int main(){
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    scanf("%d%d%d",&n,&m,&p);
    pre();
    for(int k=1;k<=p;k++) sz[k]=m/p+(m%p>=k);sz[0]=sz[p];
    for(int i=0;i<p;i++) A.s[i]=sz[i];
    for(int i=1;i<=tot&&prime[i]<=m;i++) sz[prime[i]%p]--;
    for(int i=0;i<p;i++) B.s[i]=sz[i];
    ll ans=(fpow(A,n)-fpow(B,n))%mod;if(ans<0) ans+=mod;
    printf("%lld",ans);
    return 0;
} 

 

 

 

以上是关于codevs 5964 [SDOI2017]序列计数的主要内容,如果未能解决你的问题,请参考以下文章

codevs 5963 [SDOI2017]树点染色

codevs 5967 [SDOI2017]相关分析

codevs 5965 [SDOI2017]新生舞会

[Sdoi2017]序列计数

LibreOJ #2002. 「SDOI2017」序列计数

BZOJ4818: [Sdoi2017]序列计数