Codeforces 1250E The Coronation

Posted zengzk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 1250E The Coronation相关的知识,希望对你有一定的参考价值。

解题思路

用2-SAT的思路将题目转化为:已知(n)个二元组(<x,y>),可以算出有多少属于不同二元组的元素((a,b))存在冲突,要在每个二元组(<x,y>)中选择选择一个元素,且要尽可能的少选(y),问是否可以选取(n)个两两不相互矛盾的元素,若可以输出选取方案。

经过简单的推导可以得到,对于(<x_i,y_i>)(<x_j,y_j>)

  • (x_ix_j)(不)冲突,则(y_iy_j)(不)冲突
  • (x_iy_j)(不)冲突,则(y_ix_j)(不)冲突

继续用2-SAT的思路,并结合上面的性质:

  • (x_i)仅和(x_j)冲突,则从(x_i)(y_j)连一条边,从(x_j)(y_i)连一条边;
  • (x_i)仅和(y_j)冲突,则从(x_i)(x_j)连一条边,从(y_i)(y_j)连一条边;
  • 若都不冲突则不连边;
  • 若都冲突则无解。

这样一来,我们得到了一个或多个联通块,根据之前推导的性质,对于第(i)个二元组,如果(i)的选取方法确定了,那么相同联通块里的选取方法也就都确定了,再加上不同联通块之间是互不影响的,我们只需要对每个联通块贪心的选取(y)少的方案,然后把所有联通块的答案加起来就是最终的答案了。

跑Tarjan缩点或者并查集缩点维护一下就没了。

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=110;
int n,m,k;
ll a[55],b[55]; char s[55];

int fa[N],sz[N]; bool vis[N];
int find(int x){return fa[x]==x?x:(fa[x]=find(fa[x]));}
void merge(int x,int y){
    x=find(x); y=find(y);
    if(x!=y){sz[y]+=sz[x];fa[x]=y;} 
}

inline int getsame(ll x){
    int cnt=0;
    while(x){cnt++;x-=x&(-x);}
    return m-cnt;   
}

void solve(){
    for(int i=1;i<=n;i++){
        for(int j=i+1;j<=n;j++){
            bool c1=false,c2=false;
            if(getsame(a[i]^a[j])>=k)c1=true;
            if(getsame(a[i]^b[j])>=k)c2=true;
            if(c1 && c2)continue;
            if(!c1 && !c2){printf("-1
");return;}
            if(c2)merge(i,j+n),merge(i+n,j);
            if(c1)merge(i,j),merge(i+n,j+n);
        }
    }
    vector<int>ans;
    for(int i=1;i<=n;i++){
        int fi=find(i),fin=find(i+n);
        if(fi==fin){printf("-1
");return;}
        if(vis[fi])continue;
        if(vis[fin]){ans.push_back(i);continue;}
        if(sz[fi]>sz[fin]){vis[fin]=true;ans.push_back(i);}
        else vis[fi]=true;
    }
    printf("%d
",(int)ans.size());
    for(int i:ans)printf("%d ",i); puts("");
}

int main()
{   
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d %d %d",&n,&m,&k);
        for(int i=1;i<=2*n;i++)fa[i]=i, sz[i]=(i>n?1:0), vis[i]=false;  
        for(int i=1;i<=n;i++){
            scanf("%s",s); a[i]=0; b[i]=0;
            for(int j=0;s[j];j++)a[i]*=2, a[i]+=s[j]-'0';
            reverse(s,s+m);
            for(int j=0;s[j];j++)b[i]*=2, b[i]+=s[j]-'0';
        }
        solve();
    }
    return 0;   
}

以上是关于Codeforces 1250E The Coronation的主要内容,如果未能解决你的问题,请参考以下文章

Please, upgrade your dependencies to the actual version of cor问题

Please, upgrade your dependencies to the actual version of cor问题

Please, upgrade your dependencies to the actual version of cor问题

[Err] 1064 - You have an error in your SQL syntax; check the manual that cor错误时

CodeForces 622B The Time

Educational Codeforces Round 7 F - The Sum of the k-th Powers 拉格朗日插值