最小相似度
思路不错的题目
考虑到总体的状态数只有(2^m)中,如果我们把某个串改变1位,这个改变后的串和这个串的答案就是(m-1),由此可见,每个串到另一个串都有一个距离,我们把这个距离设为改变的位数,所有串到某个串都有一个最小位数(x),这个最小位数的最大值(y)的答案(m-y)就是我们的答案。
我们发现这就是一个最短路,直接拿bfs实现,复杂度(O(n+m2^m))
然后还有一种(FWT)的做法
注意到(A xor B=CRightarrow B=A xor C)
然后我们枚举或者二分答案为(x)后(C)就是确定的了,就是(C_i=[f(i)<=x]),(f(i))表示二进制串下(1)的个数
然后(A)卷(C),如果存在(B_i=n)就说明所以的串都卷上去了,这个答案就合法
Code:(BFS):
#include <cstdio>
#include <cctype>
#include <cstring>
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int N=1<<20;
int q[N+10],dp[N],l=1,r;
int n,m;
char s[23];
int main()
{
memset(dp,-1,sizeof dp);
read(n),read(m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
int sta=0;
for(int j=1;j<=m;j++)
sta|=(s[j]=='1')<<j-1;
dp[sta]=0;
}
for(int i=0;i<1<<m;i++)
if(~dp[i])
q[++r]=i;
int ans=0;
while(l<=r)
{
int now=q[l++];
ans=ans>dp[now]?ans:dp[now];
for(int i=0;i<m;i++)
{
int v=now^(1<<i);
if(dp[v]==-1)
dp[q[++r]=v]=dp[now]+1;
}
}
printf("%d
",m-ans);
return 0;
}
Code(FWT):
#include <cstdio>
#include <cctype>
template <class T>
void read(T &x)
{
x=0;char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)) x=x*10+c-'0',c=getchar();
}
const int mod=998244353,inv=499122177;
inline int add(int a,int b){return a+b>=mod?a+b-mod:a+b;}
#define mul(a,b) (1ll*(a)*(b)%mod)
const int N=1<<20;
int n,m,A[N],B[N],d[N];
char s[23];
void FWT(int *a,int len,int typ)
{
for(int le=1;le<len;le<<=1)
for(int p=0;p<len;p+=le<<1)
for(int i=p;i<p+le;i++)
{
int x=a[i],y=a[i+le];
a[i]=add(x,y),a[i+le]=add(x,mod-y);
if(!typ) a[i]=mul(a[i],inv),a[i+le]=mul(a[i+le],inv);
}
}
bool check(int x)
{
for(int i=0;i<1<<m;i++) B[i]=d[i]<=x;
FWT(B,1<<m,1);
for(int i=0;i<1<<m;i++) B[i]=mul(A[i],B[i]);
FWT(B,1<<m,0);
for(int i=0;i<1<<m;i++)
if(B[i]==n)
return true;
return false;
}
int main()
{
read(n),read(m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
int sta=0;
for(int j=1;j<=m;j++)
sta|=(s[j]=='1')<<j-1;
++A[sta];
}
FWT(A,1<<m,1);
for(int i=1;i<1<<m;i++) d[i]=d[i>>1]+(i&1);
int l=0,r=m;
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d
",l);
return 0;
}
2019.3.2