admin管理员组

文章数量:1622630


题意:

给你n个长度为k的01串,让你构造一个串,让这个串和其他各个串相同位置上相同字符的总数的最大值最小。
(k <= 20)

思路:

首先我们最朴素的想法就是暴力枚举该串然后和n个串维护最大值最小.当然这复杂度肯定gg.
那么我们可以从反面来考虑,因为同是二进制数所以我们要构造的那个串肯定都可以由给定的这n个串经过某几位的变换得到.而且观察到两个串之间的value仅仅是相同的几位.也就是说构造的串和这n个串肯定有几位不同.
那么我们可以首先将这n个串加入队列,然后进行bfs变换某几位.那么变换位数越多那么得到的value就越小.
另外这个过程我们必须要维护该二进制第一次被n个串中的某个串变换到所需要变得位数。这是因为我们构造话不好找到中间点,即不知道何时才是最优解所以我们必须要整个过程来维护他.根据bfs的性质,一个串最早可以变换到另一个串,说明他们之间剩下的相同位数多,得到的value大,而其他串要之后才能得到该串说明位数相同的少得到的分数也少,这样就满足我们找到的一个最大值一定满足和当前串最大和其余的最少.

综上,这个过程我们直接维护整个过程中变换次数最多得到的那个串即可.(因为变换次数越多,不同位数越多相同位数越少从而保证最大值越小,PS: 这里通过异或每次使一位变得不同)

#include<bits/stdc++.h>

using namespace std;
const int maxn = 1e6+1e5+5;
struct node
{
    int num;
    int step;
    node(int x = 0,int y = 0)
    {
        num = x;
        step = y;
    }
};
int n,k;
int ans,ma;
bool vis[maxn];
void bfs()
{
    queue<node>Q;
    memset(vis,0,sizeof vis);
    while(!Q.empty()) Q.pop();
    for(int i = 1;i <= n;++i)
    {
       int x;
       int cur = 0;
       for(int j = 0;j < k;++j)
       {
           scanf("%1d",&x);
           if(x == 1)
           cur |= (1 << j);
       }
       Q.push(node(cur,0));
       vis[cur] = 1;
    }
    while(!Q.empty())
    {
        node q = Q.front();
        Q.pop();
        for(int j = 0;j < k ;++j)
        {
            node p;
            p.num = q.num ^ (1 << j);
            if(vis[p.num]) continue;
            p.step = q.step + 1;
            if(ma < p.step)
            {
                ma = p.step;
                ans = p.num;
            }
            Q.push(p);
            vis[p.num] = 1;
        }
    }
    int len = 0;
    while(ans)
    {
        printf("%d",ans & 1);
        ans >>= 1;
        len++;
    }
    while(len < k)
    {
        printf("0");
        len++;
    }
    puts("");
    return ;
}
int main()
{
    while(~scanf("%d %d",&n,&k))
    {
        ans = 0;
        ma = 0;
        bfs();
    }
    return 0;
}

本文标签: 思维GymdistinctiveBFScharacter