其他分享
首页 > 其他分享> > 8.10

8.10

作者:互联网

ABC232G

题意:

给定\(n\)个点和两个序列\(A,B\)和模数\(m\)

从\(i\)号点走到\(j\)号点的代价是\((A_i+B_j)\%m\)

问从\(1\)走到\(n\)号点的最小代价是多少

\(n\leq 2*10^5,m\leq 10^9,0\leq A_i,B_i<m\)

题解:

连边点\(i\rightarrow m-A_i,B_i\rightarrow i\)边权为\(0\)

然后对每个数字点,连边\(i\rightarrow i+1\),边权为\(1\)

这样从\(i\)走到\(j\)就刚好走了\((A_i+B_j)\%m\)

把没用的点缩点,点的数量就是\(O(n)\)的

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=1e9+7,inv2=5e8+4,inf=2e18;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m;
        cin>>n>>m;
        vector<int> q;
        vector<int> a(n+1),b(n+1);
        typedef pair<int,int> pr;

        map<int,vector<pr> > eg;
        map<int,int> dis;
        map<int,bool> vis;
        for(int i=1;i<=n;++i)
        {
            int x;cin>>x;
            eg[i].emplace_back(pr(n+1+(m-x)%m,0));
            q.emplace_back(n+1+(m-x)%m);
            dis[i]=inf;
        }
        for(int i=1;i<=n;++i)
        {
            int x;cin>>x;
            //cout<<n+1+x<<"!!"<<endl;
            eg[n+1+x].emplace_back(pr(i,0));
            q.emplace_back(n+1+x);
        }
        sort(q.begin(),q.end());
        q.erase(unique(q.begin(),q.end()),q.end());
        int pre=q[q.size()-1];
        for(int t:q)
        {
            dis[t]=inf;
            //cout<<pre<<' '<<t<<"!!"<<endl;
            eg[pre].emplace_back(pr(t,(t-pre+m)%m));
            pre=t;
        }
        auto spfa=[&](int st) -> void
        {
            priority_queue<pr,vector<pr>,greater<pr> > q;
            dis[st]=0;
            q.push(pr(0,st));
            while(!q.empty())
            {
                int now=q.top().second;
                q.pop();
                //cout<<now<<"!!!"<<endl;
                if(vis[now]) continue;
                vis[now]=1;
                for(auto [t,v]:eg[now])
                {
                    //cout<<now<<' '<<t<<' '<<v<<"!!"<<endl;
                    //cout<<dis[now]<<' '<<dis[t]<<"!!"<<endl;
                    if(dis[t]>dis[now]+v)
                    {
                        dis[t]=dis[now]+v;
                        q.push(pr(dis[t],t));
                    }
                }
            }
        };
        spfa(1);
        cout<<dis[n]<<'\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

ABC232H

题意:

给定一个\(n*m\)的棋盘,从\((1,1)\)出发,每次可以走到周围的八个格子,每个格子只能走一次。

要设计一个路线,让每条格子经过一次,且最后在\((a,b)\)结束,保证\((a,b)\neq (1,1)\)

\(n,m\leq 200,(a,b)\)在棋盘内。

题解:

什么减治构造。

考虑如果\(n=2\),那么(如果\(m=2\),那么翻转一下棋盘)

img

如果\(n\neq 2,m\neq 2\)

img

那么如果\((a,b)\)不在绿色区域内,可以先把绿色区域走完,然后把棋盘上下翻转,这样棋子又在\((1,1)\)了,变成了少了一列的子问题。

如果\((a,b)\)在绿色区域内,把棋盘转置,终点就不在绿色区域内了。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=1e9+7,inv2=5e8+4,inf=2e18;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m,a,b;
        cin>>n>>m>>a>>b;
        struct node
        {
            int x,y;
        };
        function<vector<node> (int,int,int,int)> dfs=[&](int x,int y,int a,int b) -> vector<node>
        {
            vector<node> q;
            if(x==2)
            {
                for(int i=1;i<b;++i)
                {
                    q.emplace_back((node){1,i});
                    q.emplace_back((node){2,i});
                }
                q.emplace_back((node){3-a,b});
                for(int i=b+1;i<=y;++i)
                {
                    q.emplace_back((node){1,i});
                }
                for(int i=y;i>=b+1;--i)
                {
                    q.emplace_back((node){2,i});
                }
                q.emplace_back((node){a,b});
            }
            else if((x>2&&y==2)||b==1||(a==x&&b==2))
            {
                q=dfs(y,x,b,a);
                for(auto &tmp:q) swap(tmp.x,tmp.y);
            }
            else
            {
                for(int i=1;i<=x;++i) q.emplace_back((node){i,1});
                vector<node> nxt=dfs(x,y-1,x-a+1,b-1);
                for(auto &tmp:nxt)
                {
                    tmp.x=x-tmp.x+1;
                    ++tmp.y;
                    q.emplace_back(tmp);
                }
            }
            return q;
        };
        auto ans=dfs(n,m,a,b);
        for(auto tmp:ans) cout<<tmp.x<<' '<<tmp.y<<'\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

快速沃尔什变换

或卷积:

\[c_i=\sum_{j|k=i}a_j*b_k \]

构造子集和函数\(fwt[a]=\sum_{j|i}a_j\)

满足

\[fwt[c]=\sum_{d|i=i}\sum_{j|k=d}a_j*b_k\\ =\sum_{(j|k)|i=i}a_j*b_k\\ =\sum_{j|i=i}a_j*\sum_{k|i=i}b_k\\ =fwt[a]*fwt[b] \]

满足变换后直接点值相乘。

构造方法,考虑倍增。

\(a_0\)表示长度为\(2^k\)的序列\(a\)中的前半段,\(a_1\)表示后半段

\(fwt[a]=merge(a_0,a_1+a_0)\)

\(merge\)表示拼接,\(a_0+a_1\)表示对应位置相加。

逆变换类似

\(a=merge(fwt[a_0],fwt[a_1]-fwt[a_0])\)

与卷积:

\[c_i=\sum_{j\&k=i}a_j*b_k \]

构造超集和函数\(fwt[a]=\sum_{j\&i=i}a_j\)

\[fwt[c]=\sum_{d\&i=i}\sum_{j\&k=d}a_j*b_k\\ =\sum_{(j\&k)\&i=i}a_j*b_k\\ =\sum_{j\&i}a_j*\sum_{k\&i}b_k\\ fwt[a]*fwt[b] \]

构造方法

\(fwt[a]=merge(a_0+a_1,a_1)\)

逆变换

\(a=merge(fwt[a_0]-fwt[a_1],fwt[a_1])\)

异或卷积:

\[c_i=\sum_{j\oplus k}=a_j*b_k \]

这个不太好构造

定义\(i∘j=popcount(i\&j)\ mod\ 2\),其中\(popcount(x)\)表示二进制下\(1\)的个数。

满足等式

\((i∘j) \oplus (i∘k)=i∘(j \oplus k)\)

构造一个函数\(fwt[a]=\sum_{i∘j=0}a_j-\sum_{i∘j=1}a_j\)

\[fwt[c]=\sum_{i∘d=0}c_d-\sum_{i∘d=1}c_d\\ =\sum_{i∘d=0}\sum_{j\oplus k=d,}a_j*b_k-\sum_{i∘d=1}\sum_{j\oplus k}a_j*b_k\\ =\sum_{i∘(j\oplus k)=0}a_j*b_k-\sum_{i∘(j\oplus k)=1}a_j*b_k\\ =\sum_{(i∘j)\oplus (i∘k)=0}a_j*b_k-\sum_{(i∘j)\oplus (i∘k)=1}a_j*b_k\\ =(\sum_{i∘j=1}a_j*\sum_{i∘k=1}b_k)+(\sum_{i∘j=0}a_j*\sum_{i∘k=0}b_k)-(\sum_{i∘j=1}a_j*\sum_{i∘k=0}b_k)-(\sum_{i∘j=0}*\sum_{i∘k=1}b_k)\\ =(\sum_{i∘j=0}a_j-\sum_{i∘j=1}a_j)*(\sum_{i∘k=0}b_k-\sum_{i∘k=1}b_k)\\ =fwt[a]*fwt[b] \]

虽然很抽象,但还是凑出来了。

怎么构造这个函数呢

\(fwt[a]=merge(a_0+a_1,a_0-a_1)\)

对于前半段最高位为\(0\)的段,\(0\&0=0,0\&1=0\),所以\(popcount\)后\(1\)的数量不变,直接加起来。

对于后半段,\(1\&1\)部分\(popcount\)后\(1\)的奇偶性改变一次,所以要减去。

逆变换

\(a=merge(\frac{fwt[a_0]+fwt[a_1]}{2},\frac{fwt[a_0]-fwt[a-1]}{2})\)

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=998244353,inv2=499122177,inf=2e18;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m;
        cin>>n;
        m=(1<<n);
        vector<int> a(m),b(m);
        vector<int> f(m),g(m);
        for(int i=0;i<m;++i) cin>>f[i];
        for(int i=0;i<m;++i) cin>>g[i];
        auto fwtor=[&](vector<int> &a,int inv) -> void
        {
            for(int k=1;2*k<=m;k<<=1)
            {
                for(int i=0;i<m;i+=2*k)
                {
                    for(int j=0;j<k;++j)
                    {
                        a[i+j+k]+=a[i+j]*inv+mod;
                        a[i+j+k]%=mod;
                    }
                }
            }
        };
        auto fwtand=[&](vector<int> &a,int inv) -> void
        {
            for(int k=1;2*k<=m;k<<=1)
            {
                for(int i=0;i<m;i+=2*k)
                {
                    for(int j=0;j<k;++j)
                    {
                        a[i+j]+=a[i+j+k]*inv+mod;
                        a[i+j]%=mod;
                    }
                }
            }
        };
        auto fwtxor=[&](vector<int> &a,int inv) -> void
        {
            for(int k=1;2*k<=m;k<<=1)
            {
                for(int i=0;i<m;i+=2*k)
                {
                    for(int j=0;j<k;++j)
                    {
                        int x=a[i+j],y=a[i+j+k];
                        a[i+j]=inv*(x+y)%mod;
                        a[i+j+k]=inv*(x-y+mod)%mod;
                    }
                }
            }
        };

        for(int i=0;i<m;++i) a[i]=f[i],b[i]=g[i];
        fwtor(a,1);fwtor(b,1);
        for(int i=0;i<m;++i) a[i]=a[i]*b[i]%mod;
        fwtor(a,-1);
        for(int i=0;i<m;++i) cout<<a[i]<<" \n"[i==m-1];

        for(int i=0;i<m;++i) a[i]=f[i],b[i]=g[i];
        fwtand(a,1);fwtand(b,1);
        for(int i=0;i<m;++i) a[i]=a[i]*b[i]%mod;
        fwtand(a,-1);
        for(int i=0;i<m;++i) cout<<a[i]<<" \n"[i==m-1];

        for(int i=0;i<m;++i) a[i]=f[i],b[i]=g[i];
        fwtxor(a,1);fwtxor(b,1);
        for(int i=0;i<m;++i) a[i]=a[i]*b[i]%mod;
        fwtxor(a,inv2);
        for(int i=0;i<m;++i) cout<<a[i]<<" \n"[i==m-1];

    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

Belarusian State University

题意:

给定一个正整数\(n\)和\(4n\)个正整数\(c(i,j,k)\),其中\(0\leq i<n,j,k\in[0,1]\)

对于位于\([0,2^n-1]\)之间的两个整数\(x,y\),\(x=\sum_{i=0}^{n-1}x_i2^i,y=\sum_{i=0}^{n-1}y_i2^i\)

定义\(f(x,y)=\sum_{i=0}^{n-1}c(i,x_i,y_i)2^i\)

题解:

这里的操作并不是\(fwt\),只是顺手写这个名字的变换了,它给出了确定的法则。

把\(a,b,c\)各自分成两段\(a_0,a_1,b_0,b_1,c_0,c_1\)

如果这一位的\(c_{i,j}=b\),那么\(a_i*b_j\rightarrow c_b\)

\(c_{0,0}=0,c_{0,1}=0,c_{1,0}=0,c_{1,1}=0\)

\[fwt[a]=merge(a_0+a_1,0)\\ fwt[b]=merge(b_0+b_1,0)\\ fwt[c]=merge(a_0*b_0+a_0*b_1+a_1*b_0+a_1*b_1,0)\\ =fwt[a]*fwt[b] \]

\(c_{0,0}=0,c_{0,1}=0,c_{1,0}=0,c_{1,1}=1\)

\[fwt[a]=merge(a_0+a_1,a_1)\\ fwt[b]=merge(b_0+b_1,b_1)\\ fwt[c]=merge(a_0*b_0+a_0*b_1+a_1*b_0,a_1*b_1)\\ =merge(fwt[a_0]*fwt[b_0]-fwt[a_1]*fwt[b_1],fwt[a_1]*fwt[b_1]) \]

\(c_{0,0}=0,c_{0,1}=0,c_{1,0}=1,c_{1,1}=0\)

\[fwt[a]=merge(a_0+a_1,a_1)\\ fwt[b]=merge(b_0+b_1,b_0)\\ fwt[c]=merge(a_0*b_0+a_0*b_1+a_1*b_1,a_1*b_0)\\ =merge(fwt[a_0]*fwt[b_0]-fwt[a_1]*fwt[b_1],fwt[a_1]*fwt[b_1]) \]

\(c_{0,0}=0,c_{0,1}=0,c_{1,0}=1,c_{1,1}=1\)

\[fwt[a]=merge(a_0,a_1)\\ fwt[b]=merge(b_0+b_1,b_0-b_1)\\ fwt[c]=merge(a_0*b_0+a_0*b_1,a_1*b_0+a_1*b_1)\\ =fwt[a]*fwt[b] \]

\(c_{0,0}=0,c_{0,1}=1,c_{1,0}=0,c_{1,1}=0\)

\[fwt[a]=merge(a_0+a_1,a_0)\\ fwt[b]=merge(b_0+b_1,b_1)\\ fwt[c]=merge(a_0*b_0+a_1*b_0+a_1*b_1,a_0*b_1)\\ =merge(fwt[a_0]*fwt[b_0]-fwt[a_1]*fwt[b_1],fwt[a_1]*fwt[b_1]) \]

\(c_{0,0}=0,c_{0,1}=1,c_{1,0}=0,c_{1,1}=1\)

\[fwt[a]=merge(a_0+a_1,a_0+a_1)\\ fwt[b]=merge(b_0,b_1)\\ fwt[c]=merge(a_0*b_0+a_1*b_0,a_0*b_1+a_1*b_1)\\ =fwt[a]*fwt[b] \]

\(c_{0,0}=0,c_{0,1}=1,c_{1,0}=1,c_{1,1}=0\)

\[fwt[a]=merge(a_0+a_1,a_0-a_1)\\ fwt[b]=merge(b_0+b_1,b_0-b_1)\\ fwt[c]=merge(a_0*b_0+a_1*b_1,a_0*b_1+a_1*b_0)\\ =merge(\frac{fwt[a_0]*fwt[b_0]+fwt[a_1]*fwt[b_1]}{2},\frac{fwt[a_0]*fwt[b_0]-fwt[a_1]*fwt[b_1]}{2}) \]

\(c_{0,0}=0,c_{0,1}=1,c_{1,0}=1,c_{1,1}=1\)

\[fwt[a]=merge(a_0,a_0+a_1)\\ fwt[b]=merge(b_0,b_0+b_1)\\ fwt[c]=merge(a_0*b_0,a_1*b_1+a_0*b_1+a_1*b_0)\\ =merge(fwt[a_0]*fwt[b_0],fwt[a_1]*fwt[b_1]-fwt[a_0]*fwt[b_0]) \]

\(c_{0,0}=1,c_{0,1}=0,c_{1,0}=0,c_{1,1}=0\)

\[fwt[a]=merge(a_0+a_1,a_0)\\ fwt[b]=merge(b_0+b_1,b_0)\\ fwt[c]=merge(a_0*b_1+a_1*b_0+a_1*b_1,a_0*b_0)\\ =merge(fwt[a_0]*fwt[b_0]-fwt[a_1]*fwt[b_1],fwt[a_1]*fwt[b_1]) \]

\(c_{0,0}=1,c_{0,1}=0,c_{1,0}=0,c_{1,1}=1\)

\[fwt[a]=merge(a_0-a_1,a_0+a_1)\\ fwt[b]=merge(b_0-b_1,b_0+b_1)\\ fwt[c]=merge(a_0*b_1+a_1*b_0,a_0*b_0+a_1*b_1)\\ =merge(\frac{fwt[a_0]*fwt[b_0]-fwt[a_1]*fwt[b_1]}{2},\frac{fwt[a_0]*fwt[b_0]+fwt[a_1]*fwt[b_1]}{2}) \]

\(c_{0,0}=1,c_{0,1}=0,c_{1,0}=1,c_{1,1}=0\)

\[fwt[a]=merge(a_0+a_1,a_0+a_1)\\ fwt[b]=merge(b_1,b_0)\\ fwt[c]=merge(a_0*b_1+a_1*b_1,a_0*b_0+a_1*b_0)\\ =fwt[a]*fwt[b] \]

\(c_{0,0}=1,c_{0,1}=0,c_{1,0}=1,c_{1,1}=1\)

\[fwt[a]=merge(a_0,a_0+a_1)\\ fwt[b]=merge(b_1,b_0+b_1)\\ fwt[c]=merge(a_0*b_1,a_0*b_0+a_1*b_0+a_1*b_1)\\ =merge(fwt[a_0]*fwt[b_0],fwt[a_1]*fwt[b_1]-fwt[a_0]*fwt[b_0]) \]

\(c_{0,0}=1,c_{0,1}=1,c_{1,0}=0,c_{1,1}=0\)

\[fwt[a]=merge(a_1,a_0)\\ fwt[b]=merge(b_0+b_1,b_0+b_1)\\ fwt[c]=merge(a_1*b_0+a_1*b_1,a_0*b_0+a_0*b_1)\\ =fwt[a]*fwt[b] \]

\(c_{0,0}=1,c_{0,1}=1,c_{1,0}=0,c_{1,1}=1\)

\[fwt[a]=merge(a_1,a_0+a_1)\\ fwt[b]=merge(b_0,b_0+b_1)\\ fwt[c]=merge(a_1*b_0,a_0*b_0+a_0*b_1+a_1*b_1)\\ =merge(fwt[a_0]*fwt[b_0],fwt[a_1]*fwt[b_1]-fwt[a_0]*fwt[b_0]) \]

\(c_{0,0}=1,c_{0,1}=1,c_{1,0}=1,c_{1,1}=0\)

\[fwt[a]=merge(a_1,a_0+a_1)\\ fwt[b]=merge(b_1,b_0+b_1)\\ fwt[c]=merge(a_1*b_1,a_0*b_0+a_0*b_1+a_1*b_0)\\ =merge(fwt[a_0]*fwt[b_0],fwt[a_1]*fwt[b_1]-fwt[a_0]*fwt[b_0]) \]

\(c_{0,0}=1,c_{0,1}=1,c_{1,0}=1,c_{1,1}=1\)

\[fwt[a]=merge(0,a_0+a_1)\\ fwt[b]=merge(0,b_0+b_1)\\ fwt[c]=merge(0,a_0*b_0+a_0*b_1+a_1*b_0+a_1*b_1)\\ =fwt[a]*fwt[b] \]

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
#define y1 (ZIMA)
    const int N=1e6+10,mod=998244353,inv2=499122177,inf=2e18;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m;
        cin>>n;
        m=(1<<n);
        vector<int> opt(n+1);
        for(int i=0;i<n;++i)
        {
            string s;cin>>s;
            opt[i]=(s[0]-'0')*8+(s[1]-'0')*4+(s[2]-'0')*2+(s[3]-'0');
        }
        vector<int> a(m),b(m);
        for(int i=0;i<m;++i)
        {
            cin>>a[i];
        }
        for(int i=0;i<m;++i)
        {
            cin>>b[i];
        }
        auto fwt=[&](vector<int> &a,vector<int> &b) -> void
        {
            for(int t=0,k=1;t<n;++t,k<<=1)
            {
                for(int i=0;i<m;i+=2*k)
                {
                    for(int j=0;j<k;++j)
                    {
                        int x1=a[i+j],y1=a[i+j+k],x2=b[i+j],y2=b[i+j+k];
                        if(opt[t]==0)
                        {
                            a[i+j]+=y1;a[i+j+k]=0;
                            b[i+j]+=y2;b[i+j+k]=0;
                        }
                        if(opt[t]==1)
                        {
                            a[i+j]+=y1;
                            b[i+j]+=y2;
                        }
                        if(opt[t]==2)
                        {
                            a[i+j]+=y1;a[i+j+k]=y1;
                            b[i+j]+=y2;b[i+j+k]=x2;
                        }
                        if(opt[t]==3)
                        {
                            b[i+j]=b[i+j+k]=x2+y2;
                        }
                        if(opt[t]==4)
                        {
                            a[i+j]+=y1;a[i+j+k]=x1;
                            b[i+j]+=y2;b[i+j+k]=y2;
                        }
                        if(opt[t]==5)
                        {
                            a[i+j]=a[i+j+k]=x1+y1;
                        }
                        if(opt[t]==6)
                        {
                            a[i+j]=x1+y1,a[i+j+k]=x1-y1;
                            b[i+j]=x2+y2,b[i+j+k]=x2-y2;
                        }
                        if(opt[t]==7)
                        {
                            a[i+j+k]+=x1;
                            b[i+j+k]+=x2;
                        }
                        if(opt[t]==8)
                        {
                            a[i+j]+=y1;a[i+j+k]=x1;
                            b[i+j]+=y2;b[i+j+k]=x2;
                        }
                        if(opt[t]==9)
                        {
                            a[i+j]=x1-y1,a[i+j+k]=x1+y1;
                            b[i+j]=x2-y2,b[i+j+k]=x2+y2;
                        }
                        if(opt[t]==10)
                        {
                            a[i+j]=a[i+j+k]=x1+y1;
                            b[i+j]=y2,b[i+j+k]=x2;
                        }
                        if(opt[t]==11)
                        {
                            a[i+j+k]+=x1;
                            b[i+j]=y2,b[i+j+k]+=x2;
                        }
                        if(opt[t]==12)
                        {
                            a[i+j]=y1,a[i+j+k]=x1;
                            b[i+j]=b[i+j+k]=x2+y2;
                        }
                        if(opt[t]==13)
                        {
                            a[i+j]=y1,a[i+j+k]=x1+y1;
                            b[i+j+k]=x2+y2;
                        }
                        if(opt[t]==14)
                        {
                            a[i+j]=y1,a[i+j+k]=x1+y1;
                            b[i+j]=y2,b[i+j+k]=x2+y2;
                        }
                        if(opt[t]==15)
                        {
                            a[i+j+k]+=x1;
                            b[i+j+k]+=x2;
                            a[i+j]=b[i+j]=0;
                        }
                    }
                }
            }
        };
        auto ifwt=[&](vector<int> &a) -> void
        {
            for(int t=0,k=1;t<n;++t,k<<=1)
            {
                
                for(int i=0;i<m;i+=2*k)
                {
                    for(int j=0;j<k;++j)
                    {
                        int x=a[i+j],y=a[i+j+k];
                        if(opt[t]==0) break;
                        if(opt[t]==1)
                        {
                            a[i+j]-=y;
                        }
                        if(opt[t]==2)
                        {
                            a[i+j]-=y;
                        }
                        if(opt[t]==3) break;
                        if(opt[t]==4)
                        {
                            a[i+j]-=y;
                        }
                        if(opt[t]==5) break;
                        if(opt[t]==6)
                        {
                            a[i+j]=(x+y)/2,a[i+j+k]=(x-y)/2;
                        }
                        if(opt[t]==7)
                        {
                            a[i+j+k]-=x;
                        }
                        if(opt[t]==8)
                        {
                            a[i+j]-=y;
                        }
                        if(opt[t]==9)
                        {
                            a[i+j]=(y-x)/2,a[i+j+k]=(x+y)/2;
                        }
                        if(opt[t]==10) break;
                        if(opt[t]==11)
                        {
                            a[i+j+k]-=x;
                        }
                        if(opt[t]==12) break;
                        if(opt[t]==13)
                        {
                            a[i+j+k]-=x;
                        }
                        if(opt[t]==14)
                        {
                            a[i+j+k]-=x;
                        }
                        if(opt[t]==15) break;

                    }
                }
            }
        };
        fwt(a,b);
        
        for(int i=0;i<m;++i) a[i]=a[i]*b[i];
        ifwt(a);
        for(int i=0;i<m;++i) cout<<a[i]<<' ';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

CF662C

题意:

有一个 \(n\) 行 \(m\) 列的表格,每个元素都是 \(0/1\) ,每次操作可以选择一行或一列,把 \(0/1\) 翻转,即把 \(0\) 换为 \(1\) ,把 \(1\) 换为 \(0\) 。请问经过若干次操作后,表格中最少有多少个 \(1\) 。

题解:

观察到行数很少,考虑枚举对哪些行进行了反转,那么复杂度是\(O(2^n)\)

然后每一列只要贪心就行。这样复杂度\(O(2^n*m)\)

考虑优化,设\(f[x]\)表示二进制数\(x\)中\(0\)和\(1\)个数的最小值

那么把枚举哪一列变成枚举某个值出现的次数,\(g[i]\)表示\(i\)出现的次数

\[ans[x]=\sum_{i=0}^{2^n-1}g[i]*f[y]*[x\oplus i==y]\\ ans[x]=\sum_{i=0}^{2^n-1}g[i]*f[y]*[x==i\oplus y] \]

然后直接异或卷积。

#include<bits/stdc++.h>
using namespace std;
namespace red{
#define int long long
#define double long double
#define ls(p) (p<<1)
#define rs(p) (p<<1|1)
#define lowbit(i) ((i)&(-i))
#define mid ((l+r)>>1)
#define eps (1e-15)
    const int N=1e6+10,mod=998244353,inv2=499122177,inf=2e18;
    void __init(int n=2000) {}
    
    inline void main()
    {
        int n,m;
        cin>>n>>m;
        int maxn=(1<<n);
        vector s(n,vector<int>(m));
        vector<int> a(maxn),b(maxn);
        for(int i=0;i<n;++i)
        {
            for(int j=0;j<m;++j)
            {
                char ch;cin>>ch;
                s[i][j]=ch^48;
            }
        }
        for(int j=0;j<m;++j)
        {
            int tmp=0;
            for(int i=0;i<n;++i)
            {
                tmp|=s[i][j]*(1<<i);
            }
            ++a[tmp];
        }
        for(int i=0;i<maxn;++i)
        {
            b[i]=__builtin_popcount(i);
            b[i]=min(b[i],n-b[i]);
        }
        
        auto fwtxor=[&](vector<int> &a,int inv) -> void
        {
            for(int k=1;2*k<=maxn;k<<=1)
            {
                for(int i=0;i<maxn;i+=2*k)
                {
                    for(int j=0;j<k;++j)
                    {
                        int x=a[i+j],y=a[i+j+k];
                        a[i+j]=inv*(x+y)%mod;
                        a[i+j+k]=inv*(x-y+mod)%mod;
                    }
                }
            }
        };
        fwtxor(a,1);fwtxor(b,1);
        for(int i=0;i<maxn;++i) a[i]=a[i]*b[i]%mod;
        fwtxor(a,inv2);
        int ans=inf;
        for(int i=0;i<maxn;++i) ans=min(ans,a[i]);
        cout<<ans<<'\n';

    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    red::__init();
    int qwq=1; //cin>>qwq;
    while(qwq--) red::main();
    return 0;
}
/*

*/

标签:int,sum,merge,void,fwt,8.10,define
来源: https://www.cnblogs.com/knife-rose/p/16575579.html