牛客练习赛41 最小相似度 解题报告

最小相似度

思路不错的题目

考虑到总体的状态数只有\(2^m\)中,如果我们把某个串改变1位,这个改变后的串和这个串的答案就是\(m-1\),由此可见,每个串到另一个串都有一个距离,我们把这个距离设为改变的位数,所有串到某个串都有一个最小位数\(x\),这个最小位数的最大值\(y\)的答案\(m-y\)就是我们的答案。

我们发现这就是一个最短路,直接拿01bfs实现,复杂度\(O(n+m2^m)\)

然后还有一种\(FWT\)的做法

注意到\(A \ xor \ B=C\Rightarrow 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\n",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\n",l);
    return 0;
}

2019.3.2

猜你喜欢

转载自www.cnblogs.com/butterflydew/p/10459737.html