• 【题解】LOJ #6488 数表【FWT】


    题目链接

    题意

    (n imes m) 的表格,一次操作可以将一行或一列在模 (4) 意义下加 (1),问任意次操作后表格内数之和的最小值。(nleq 10,mleq 10^4)

    题解

    行上的操作确定后,每一列都容易确定最优解。

    (c(i)) 为列上状态为 (i) 的列的个数,(f(i)) 为当一列为 (i) 时,做列操作后的最小和。二者做减法卷积便能得到每种行操作下的最优答案。

    (4) 进制的高维循环卷积类似于异或卷积,但在循环内要做长为 (4) DFT(暴力即可)

    减法卷积在翻转系数时怎么做都能过,但大多数写法得到的结果顺序其实是乱的。

    #include<bits/stdc++.h>
    using namespace std;
    const int N=21;
    int f[1<<N],c[1<<N],rt=86583718,mod=998244353,inv4=(mod*3ll+1)/4;
    int a[11][10001];
    
    int p[4],q[4];
    void dft(int tp){
        int r=1;
        for(int i=0;i<4;i++){
            q[i]=0;
            for(int j=3;j>=0;j--)
                q[i]=(q[i]*1ll*r+p[j])%mod;
            r=r*1ll*rt%mod;
        }
        if(tp==-1){
            swap(q[1],q[3]);
            for(int i=0;i<4;i++)q[i]=q[i]*1ll*inv4%mod;
        }
    }
    void fwt(int *a,int lim,int tp){
        for(int i=1;i<lim;i<<=2){
            for(int j=0;j<lim;j+=i<<2){
                for(int k=0;k<i;k++){
                    // cerr<<"| "<<j+k<<" "<<i<<endl;
                    for(int l=0;l<4;l++)p[l]=a[i*l+j+k];
                    dft(tp);
                    for(int l=0;l<4;l++)a[i*l+j+k]=q[l];
                }
            }
        }
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++)for(int j=0;j<m;j++)scanf("%d",a[i]+j);
        for(int i=0;i<m;i++){
            int s=0;
            for(int j=0;j<n;j++)
                s=(s<<2)|((4-a[j][i])&3);
            c[s]++;
            // if(s)c[(1<<(n*2))-s]++;
            // else c[0]++;
        }
        for(int i=0;i<(1<<n*2);i++){
            int mn=0x7f7f7f7f;
            for(int j=0;j<4;j++){
                int s=0;
                for(int k=0;k<n;k++)
                    s+=((i>>(k*2))+j)&3;
                mn=min(s,mn);
            }
            f[i]=mn;
        }
        // for(int i=0;i<1<<(n*2);i++)cerr<<"! "<<c[i];cerr<<endl;
        fwt(f,1<<(n*2),1);
        fwt(c,1<<(n*2),1);
        // for(int i=0;i<1<<(n*2);i++)cerr<<"! "<<c[i];cerr<<endl;
        for(int i=0;i<1<<(n*2);i++)f[i]=f[i]*1ll*c[i]%mod;
        fwt(f,1<<(n*2),-1);
        int ans=0x7f7f7f7f;
        for(int i=0;i<1<<(n*2);i++)ans=min(ans,f[i]);
        cout<<ans;
    }
    
    
  • 相关阅读:
    软件测试面试题(一)
    测试面试题
    测试
    测试理论
    软件测试的认识
    理论知识
    H5页面的测试方式
    mysql数据库,linux,面试理论等
    登录设计点
    ATM境外取款测试点
  • 原文地址:https://www.cnblogs.com/wallbreaker5th/p/14190665.html
Copyright © 2020-2023  润新知