BZOJ3992 / LG3321 "SDOI2015" シーケンス統計DP + NTT

問題の説明

Cの小さなセットがある\(S \)未満の要素である、\(M \)非負整数。彼は、番組シリーズジェネレータを書いた長さを発生させることができる(\ Nを)\列数、各列のカウントはすべてセットされている\(S \)

これらの列の多くを生成するための小型発電機とC。しかし、小さなCが問題の必要性あなたの助けがあります。与えられた整数\(Xを\) すべてが出て生成され、すべての数字の列数の積を満たすことができることを要求(\ BMOD M \)は\に等しいです\(X \)列のどのように多くの同じ番号があります。小さなCつまり、二つの列(\ \ {a_iを\} \ ) と\(\ {B_i \} \ ) 異なる場合にのみ存在する場合、整数少なくとも(I \)\、満足\(a_iを\ NEQ B_i \ )彼は彼だけが答えを見つけるためにあなたを必要としますので、また、小さなCは、答えは大きいかもしれないと思います(\ MOD 1004535809 \)\それに値を。

BZOJ3992

LG3321


問題の解決策

良い質問!

最初のサブセクション- \(O(NM ^ 2)\) \(\ \ {} DPをmathrm)

セット\(DP [I] [J ] \) の代表的な選択\(I \)膜後\(M \)\(J \)プログラム番号。

伝達方程式:\(DP [I] [J] = \ SUM \ limits_ {K = 1} ^ {| S |} {\ SUM \ limits_ {P = 0} ^ {M-1} {DP [I-1。 ] [S_K \回P \ BMOD M]}} \)

境界条件:\(DP [J] = [J \ S IN] \ [1])

時間複雑\(O(NM ^ 2)\) 所望のスコア(\ 10 \)ポイント。

第2のサブクラス部分- \(O(M ^ 2 \ N-log_2)\) \(\ \ {} DPをmathrm)

セット\(F [I] [J ] \) 選択の代表\(2 ^ I \)膜後\(M \)\(J \)プログラム番号。

前処理\(fは\)に類似した後、電源をすることができ、迅速に解決しました。

正解

第二種のサブセクションのために、中に見出さ\(\ SUM \)\(A \ B = Cタイムズ\) 処理は非常に良好ではありません。

対数のために考慮するので、\(A = log_g A \)であった(A + B = C \)\、畳み込み、NTTを最適化することができます。

マッピング関係、フィルムとして\(M \)の意味で、原始根の性質に応じて、対数的に変換することができる\(G {A} ^ \ BMOD M \)、\ (A \)の範囲\ ([0、M-1)\)

NTTは、その後、いくつかの詳細はまだ考える必要があり実現しました。


\(\ mathrm {コード} \)

10pts

#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh=1;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') fh=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=fh;
}

const int maxS=8000+7;
const int mod=1004535809;

int n,m,x,S;
int a[maxS];

void Init(void){
    read(n);read(m);read(x);read(S);
    for(int i=1;i<=S;i++) read(a[i]);
}

int dp[1007][maxS];

void Work(void){
    for(int i=1;i<=S;i++) dp[1][a[i]]++;
    for(int i=2;i<=n;i++){
        for(int j=1;j<=S;j++){
            for(int k=0;k<m;k++){
                int p=(long long)k*a[j]%m;
                dp[i][p]=(dp[i][p]+dp[i-1][k])%mod;
            }
        }
    }
    printf("%d\n",dp[n][x]);
}

int main(){
    Init();Work();
    return 0;
}

60pts

#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh=1;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') fh=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=fh;
}

const int maxS=8000+7;
const int mod=1004535809;

int n,m,x,S;
int a[maxS];
int dp[maxS],opt[maxS];
//bool exist[maxS];

void Init(void){
    read(n);read(m);read(x);read(S);
    for(int i=1;i<=S;i++) read(a[i]),dp[a[i]]=1;
}

int tmp[maxS];

int power(int x,int p,int mod){
    int res(1);
    while(p){
        if(p&1) res=(long long)res*x%mod;p>>=1;
        x=(long long)x*x%mod;
    }
    return res;
}

void mul(int *f,int *g,int *res){
    for(int i=0;i<m;i++){
    //  if(!exist[i]) continue;
        for(int j=0;j<m;j++){
            int p=(long long)i*j%m;
            tmp[p]=(tmp[p]+(long long)f[i]*g[j]%mod)%mod;
        }
    }
    for(int i=0;i<m;i++) res[i]=tmp[i],tmp[i]=0;
}

void fpow(int p){
    while(p){
        if(p&1) mul(dp,opt,opt);
        mul(dp,dp,dp);p>>=1;
    }
}

void Work(void){
    opt[1]=1;fpow(n);
    printf("%d\n",opt[x]);
}

int main(){
    Init();
    Work();
    return 0;
}

100pts

#include<bits/stdc++.h>
using namespace std;

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh=1;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') fh=-1,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    x*=fh;
}

const int maxS=16000+7;
const int mod=1004535809;

int n,m,x,S;
int a[maxS];
int dp[maxS<<1],opt[maxS<<1];

int power(int x,int p,int mod){
    int res(1);
    while(p){
        if(p&1) res=(long long)res*x%mod;p>>=1;
        x=(long long)x*x%mod;
    }
    return res;
}

bool check(int g,int p){
    int q=p-1;
    for(int i=2;(long long)i*i<=q;i++){
        if(q%i==0&&(power(g,i,p)==1||power(g,q/i,p)==1)) return false;
    }
    return true;
}

int getG(int k){
    for(int i=2;i<=100;i++) if(check(i,k)) return i;
    return -1;
}

int pos[maxS];
int Gm,Gd=3;
int invG=power(Gd,mod-2,mod);

int tr[maxS<<1];
int lim;

void NTT(int *f,int type){
    for(int i=0;i<lim;i++) if(i<tr[i]) swap(f[i],f[tr[i]]);
    for(int dlen=2;dlen<=lim;dlen<<=1){
        int len=dlen>>1,w;
        if(type==1) w=power(Gd,(mod-1)/dlen,mod);
        else w=power(invG,(mod-1)/dlen,mod);
        for(int k=0;k<lim;k+=dlen){
            int buf=1;
            for(int l=0;l<len;l++){
                int LF=f[k+l],RF=(long long)buf*f[len+k+l]%mod;
                f[k+l]=(LF+RF)%mod,f[k+l+len]=(LF-RF+mod)%mod;
                buf=(long long)buf*w%mod;
            }
        }
    }
    if(type==-1){
        int inv=power(lim,mod-2,mod);
        for(int i=0;i<lim;i++) f[i]=(long long)f[i]*inv%mod;
    }
}

void Init(void){
    read(n);read(m);read(x);read(S);
    Gm=getG(m);
//  printf("** GM = %d , invG = %d\n",Gm,invG);
    for(int i=0;i<m-1;i++){
        int Pos=power(Gm,i,m);
        pos[Pos]=i;
    }
    for(int i=1;i<=S;i++){
        read(a[i]);
        if(a[i]) dp[pos[a[i]]]++;
    }
//  for(int i=1;i<=m;i++){
//      printf("%d %d\n",dp[i],pos[i]);
//  }
}

int tmp[maxS],FF[maxS<<1],GG[maxS<<1];

void mul(int *f,int *g,int *res){
    for(int i=0;i<lim;i++) FF[i]=f[i],GG[i]=g[i];
    NTT(FF,1);NTT(GG,1);
    for(int i=0;i<lim;i++) FF[i]=(long long)FF[i]*GG[i]%mod;
    NTT(FF,-1);
    for(int i=0;i<m-1;i++) res[i]=(FF[i]+FF[i+m-1])%mod;
}

void fpow(int p){
    while(p){
        if(p&1) mul(opt,dp,opt);
        mul(dp,dp,dp);p>>=1;
    }
}

void Work(void){
    for(lim=1;lim<=m*2;lim<<=1);
//  printf("** lim = %d\n",lim);
    for(int i=0;i<lim;i++) tr[i]=(tr[i>>1]>>1)|((i&1)?lim>>1:0);
    opt[pos[1]]=1;fpow(n);
    printf("%d\n",opt[pos[x]]);
}

int main(){
//  printf("**%d\n",getG(12289)); 
    Init();
    Work();
    return 0;
}

おすすめ

転載: www.cnblogs.com/liubainian/p/12151558.html