ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

8.10

2022-08-11 12:00:08  阅读:133  来源: 互联网

标签:int sum merge void fwt 8.10 define


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

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有