标签:Binary min int ll CF662C FWTXOR 异或 Ans 2n
CF662C Binary Table
题解
观察数据范围,发现 n n n 很小, m m m 很大, m m m 大约在 2 n 2^n 2n 级别,这很明显地启示我们把01矩阵转化为长度为 m m m 的数列来想。
把行和列颠倒过来显然不影响结果。这个时候我们不妨把每一行的01序列看作一个 2 n 2^n 2n 以内的数的二进制表示,那么对某一列的操作相当于把每个数都异或上一个 2 的次幂,对所有列的操作可以等价于对每个数都异或上一个 [ 0 , 2 n ) [0,2^n) [0,2n) 的值。
现在我们假设这个值是固定的,那么就只剩下行的操作。这个时候每个数显然可以独立判断是否反转,往1的个数少的那边转即可。
由此我们可以形式化地写出答案:设
f
(
x
)
f(x)
f(x) 表示数
x
x
x 进行了0/1次反转后的最少的1的数量,长度为
m
m
m 的数列
a
i
a_i
ai 标号为
0
∼
m
−
1
0\sim m-1
0∼m−1,那么有
A
n
s
=
min
x
∈
[
0
,
2
n
)
{
∑
i
=
0
m
−
1
f
(
a
i
x
o
r
x
)
}
Ans=\min_{x\in [0,2^n)}\{\sum_{i=0}^{m-1}f(a_i \,xor\,x)\}
Ans=x∈[0,2n)min{i=0∑m−1f(aixorx)}
这好像有点像可以异或卷积的样子?我们不妨把式子再变一下:设
b
i
b_i
bi 表示数列
a
a
a 中数
i
i
i 出现的次数,那么
A
n
s
=
min
x
∈
[
0
,
2
n
)
{
∑
i
=
0
2
n
−
1
f
(
i
x
o
r
x
)
⋅
b
i
}
Ans=\min_{x\in [0,2^n)}\{\sum_{i=0}^{2^n-1}f(i \,xor\,x)\cdot b_i\}
Ans=x∈[0,2n)min{i=0∑2n−1f(ixorx)⋅bi}
由异或的性质可得
A
n
s
=
min
x
∈
[
0
,
2
n
)
{
∑
i
x
o
r
j
=
x
f
(
j
)
⋅
b
i
}
Ans=\min_{x\in [0,2^n)}\{\sum_{i\,xor\,j=x}f(j)\cdot b_i\}
Ans=x∈[0,2n)min{ixorj=x∑f(j)⋅bi}
这样就完全是异或卷积的样子了,直接做一遍异或卷积即可。
代码
#include<bits/stdc++.h>//JZM yyds!!
#define ll long long
#define uns unsigned
#define IF (it->first)
#define IS (it->second)
#define END putchar('\n')
using namespace std;
const int MAXN=(1<<20)+5;
const ll INF=1e18;
inline ll read(){
ll x=0;bool f=1;char s=getchar();
while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();}
while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+(s^48),s=getchar();
return f?x:-x;
}
int ptf[30],lpt;
inline void print(ll x,char c='\n'){
if(x<0)putchar('-'),x=-x;
ptf[lpt=1]=x%10;
while(x>9)x/=10,ptf[++lpt]=x%10;
while(lpt)putchar(ptf[lpt--]^48);
putchar(c);
}
const ll MOD=1e9+7;//习惯性取模
int n,m,k,in[MAXN];
char s[MAXN];
ll a[MAXN],b[MAXN],c[MAXN],ans;
inline void FWTXOR(ll*a,int n,int inv){
ll in2=inv>0?1:((MOD+1)>>1),a0,a1;
for(int k=n;k>1;k>>=1)
for(int i=0,d=k>>1;i<n;i+=k)
for(int j=i;j<i+d;j++)
a0=a[j],a1=a[j+d],a[j]=(a0+a1)*in2%MOD,a[j+d]=(a0-a1+MOD)*in2%MOD;
}
signed main()
{
m=read(),n=read();
for(int j=0;j<m;j++){
scanf("%s",s);
for(int i=0;i<n;i++)if(s[i]=='1')in[i]|=(1<<j);
}
k=(1<<m);
for(int i=0;i<n;i++)a[in[i]]++;
for(int i=0;i<k;i++)b[i]=b[i>>1]+(i&1);
for(int i=0;i<k;i++)b[i]=min(b[i],m-b[i]);
FWTXOR(a,k,1),FWTXOR(b,k,1);
for(int i=0;i<k;i++)c[i]=a[i]*b[i]%MOD;
FWTXOR(c,k,-1);
ans=n*m;
for(int i=0;i<k;i++)ans=min(ans,c[i]);
print(ans);
return 0;
}
标签:Binary,min,int,ll,CF662C,FWTXOR,异或,Ans,2n 来源: https://blog.csdn.net/weixin_43960287/article/details/122311079
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。