CF300Dはスクエア絵画

スクエア絵画

https://codeforces.com/problemset/problem/300/D

彼は、より複雑であるが、本質的に非常に単純なフラクタルを理解するために与えました。

問題の解決策

明らかに、3未満の奇数の正方形と動作させることができ、各時間動作のみ辺の長さのみである:中央正方形の4つの等しい大きさの小さな正方形に。

我々は、操作の数がMであるせ、そしてNを低減することができる分割数の二乗の大きさを表す(すなわち、最小値が存在する各正方形を分割する)、\ (dp_は、{M、K}が\)正方形Mの操作の数を表します。 、プログラムオペランドK回。

则有:
\ [dp_ {M、K} = \ sum_ {iが+ J + K + L = K-1} dp_ {M-1、I} * dp_ {M-1、J} * dp_ {M-1 、K} * dp_ {M-1、L} \]

7340033のNTT弾性率は、元のルートに、である。3、NTT畳み込みを転送することができます。

Oの時間複雑度(QログN + KログNログK)。

CO int N=4096;
int dp[31][N],tmp[N];
int rev[N],omg[N];

void NTT(int a[],int lim){
    for(int i=0;i<lim;++i)
        if(i<rev[i]) swap(a[i],a[rev[i]]);
    for(int i=1;i<lim;i<<=1)
        for(int j=0;j<lim;j+=i<<1)
            for(int k=0;k<i;++k){
                int t=mul(omg[lim/(i<<1)*k],a[j+i+k]);
                a[j+i+k]=add(a[j+k],mod-t),a[j+k]=add(a[j+k],t);
            }
}
int main(){
    int len=log2(N),lim=N;
    for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
    omg[0]=1,omg[1]=fpow(3,(mod-1)/lim);
    for(int i=2;i<lim;++i) omg[i]=mul(omg[i-1],omg[1]);
    dp[0][0]=1;
    for(int i=1;i<31;++i){
        copy(dp[i-1],dp[i-1]+lim,tmp);
        NTT(tmp,lim);
        for(int j=0;j<lim;++j) tmp[j]=fpow(tmp[j],4);
        omg[0]=1,omg[1]=fpow(omg[1],mod-2);
        for(int i=2;i<lim;++i) omg[i]=mul(omg[i-1],omg[1]);
        NTT(tmp,lim);
        dp[i][0]=1;
        int ilim=fpow(lim,mod-2);
        for(int j=1;j<1005;++j) dp[i][j]=mul(tmp[j-1],ilim); // edit 1
        omg[0]=1,omg[1]=fpow(omg[1],mod-2);
        for(int i=2;i<lim;++i) omg[i]=mul(omg[i-1],omg[1]);
    }
    for(int q=read<int>();q--;){
        int n=read<int>(),k=read<int>();
        int m=0;
        for(;n>1 and n&1;n>>=1) ++m;
        printf("%d\n",dp[m][k]);
    }
    return 0;
}

暴力次元コンボリューションにもかかわらず、第二の値が1000のDPは問題ではないよりも大きいが、前者DPは1000レコードのみを記録する場合、間違ったバックを記録します。とき DPの背面の記録された値が、その後、補間の数は巡回畳み込みで、その結果、十分なされていない場合ので、これはおそらくです。

おすすめ

転載: www.cnblogs.com/autoint/p/12013923.html