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\),那么翻转一下棋盘)
如果\(n\neq 2,m\neq 2\)
那么如果\((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