专栏文章

题解:AT_abc396_g [ABC396G] Flip Row or Col

AT_abc396_g题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipvc4am
此快照首次捕获于
2025/12/03 18:33
3 个月前
此快照最后确认于
2025/12/03 18:33
3 个月前
查看原文

思路

我们先转换一下题意:给你一个数组 aa 包含 nn 个长度为 mm 的二进制数,让你找出一个二进制数 ss 满足 min(popcount(aixors),mpopcount(aixors))\sum{\min(\operatorname{popcount}(a_i\operatorname{xor} s),m-\operatorname{popcount}(a_i\operatorname{xor} s))} 的值最小,并且输出那个值。
我们定义 fs,if_{s,i} 表示对于二进制数 ss 和数字 ii 来说,aa 中有多少个数字和 ss汉明距离恰好为 ii
最后转移的式子如下: fs,i=1i×popcount(txors)=1k=0i1[ki不同奇偶]×ft,k[ki同奇偶]×fs,kf_{s,i}=\frac{1}{i}\times\sum_{\operatorname{popcount}(t\operatorname{xor} s)=1}{\sum_{k=0}^{i-1}{[k和i不同奇偶]\times f_{t,k}-[k和i同奇偶]\times f_{s,k}}}
当然这个式子还是太抽象了,大概说一下含义。
假设每个二进制数都是一个点,然后与之汉明距离为 11 的点连一条边,再设置该点权值为 aa 中出现多少次该点,那么 fs,if_{s,i} 就是距离 ssii 的点的权值之和。
我们先加上 ft,i1\sum{f_{t,i-1}} 的值,发现算重了走过 ss 的路径,所以减去 m×fs,i2m\times\sum{f_{s,i-2}},后面以此类推。
然而算完之后却发现多算了好多。这是因为对于每条路径,都有 ii 种开始的方法,也就是乘上 1i\frac{1}{i} 就可以了。
最终复杂度 O(2M×M3)O(2^M\times M^3),当然显然可以优化掉一个 MM,但没必要。
CPP
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=18,inf=1e18;
int n,m,f[(1<<N)+2][N+2];
int ans;
signed main(){
	ios::sync_with_stdio(false);cin.tie(0);
	cin>>n>>m;
	ans=inf;
	for(int i=1;i<=n;i++){
		int x=0;
		for(int j=1;j<=m;j++){
			char y;cin>>y;
			x=(x<<1)|(y-'0');
		}
		f[x][0]++;
	}
	for(int i=1;i<=m;i++){
		for(int s=0;s<1<<m;s++){
			for(int j=1;j<=m;j++){
				int t=s^(1<<j-1);
				for(int k=i-1;k>=0;k--){
					if((i^k)&1)f[s][i]+=f[t][k];
					else f[s][i]-=f[s][k];
				}
			}
			f[s][i]/=i;
		}
	}
	for(int s=0;s<1<<m;s++){
		int num=0;
		for(int i=0;i<=m;i++)num+=min(i,m-i)*f[s][i];
		ans=min(ans,num);
	}
	cout<<ans<<"\n";
	return 0;
}
顺带,这题评紫真的合适吗……

评论

0 条评论,欢迎与作者交流。

正在加载评论...