首页 > 其他分享 >CodeForces 1250E [2-sat]

CodeForces 1250E [2-sat]

时间:2023-05-31 10:03:58浏览次数:64  
标签:匹配 int 反转 CodeForces tot fa 1250E mx sat


题目链接:https://codeforces.com/contest/1250/problem/E

 

解题思路:

首先根据反转的性质有:

       有字符串a,b,a的反转A,b的反转B,如果a和b匹配值为K,那么A和B的值也为K

        同样a和B匹配值为M,那么A和b的匹配值也为M,因此有对称性

那么就可以转换成2-sat问题了,设点i的对立点集是i+n,也就是a和A

       如果i和j不管怎么反转都能匹配,那么他们之间就没有约束关系

       如果i和j不管怎么反转都不匹配,那么直接是无解的

       如果i只能和j匹配,不能和j+n匹配,那么联合i和j,联合i+n,j+n

       如果只能和j+n匹配,那么联合i和j+n,联合i+n,j

这个就可以用并查集维护,然后因为我们需要更少的反转,所以加上加权并查集,选择权值较小的i集合或者i+n集合

#include<bits/stdc++.h>
using namespace std;
const int mx = 100+5;
const int mod = 1e9 + 7; 
typedef long long ll;
int n,m,K;
int fa[mx],siz[mx],ans[mx];
char s[mx][mx];
vector <int> g[mx];
int find(int x) {
	return x==fa[x]?x:fa[x]=find(fa[x]);
}
bool check(int u,int v) {
	int cnt = 0;
	for (int i=0;i<m;i++)
		cnt += s[u][i] == s[v][i];
	return cnt >= K;
}
bool solve() {
	for (int i=0;i<n;i++) {
		for (int j=i+1;j<n;j++) {
			bool ok1 = check(i,j);
			bool ok2 = check(i,j+n);
			if (!ok1 && !ok2) return 0;
			if (ok1 && ok2) continue;
			int fi = find(i),fj = find(j);
			int fi_n = find(i+n),fj_n = find(j+n);
			if (ok2) swap(fj,fj_n);
			if (fi == fj_n) return 0;
			if (fi != fj) {
				fa[fj] = fi;
				siz[fi] += siz[fj];
				fa[fj_n] = fi_n;
				siz[fi_n] += siz[fj_n]; 
			}
		}
	}
	return 1;
}
int main(){
	int t;
	scanf("%d",&t);
	while (t--) {
		scanf("%d%d%d",&n,&m,&K);
		for (int i=0;i<2*n;i++) {
			fa[i] = i;
			siz[i] = i >= n;
			g[i].clear();
		}
		for (int i=0;i<n;i++) {
			scanf("%s",s[i]);
			reverse(s[i],s[i]+m);
			memcpy(s[i+n],s[i],m+1);
			reverse(s[i],s[i]+m);
		}
		bool ok = solve();
		if (!ok) puts("-1");
		else {
			vector <int> ve;
			int tot = 0;
			for (int i=0;i<2*n;i++) {
				int fi = find(i);
				g[fi].push_back(i);
			}
			for (int i=0;i<n;i++) {
				int fi = find(i);
				int fi_n = find(i+n);
				if (fi != i) continue;
				if (siz[fi] <= siz[fi_n]) ve.push_back(fi);
				else ve.push_back(fi_n);
			}
			for (int u : ve) {
				for (int v :g[u])
					if (v >= n) ans[tot++] = v - n + 1;
			}
			if (!tot) puts("0\n");
			else {
				printf("%d\n",tot);
				for (int i=0;i<tot;i++)	
					printf("%d%c",ans[i],i==tot-1?'\n':' ');
			} 
		}
	}
	return 0;
}

 

标签:匹配,int,反转,CodeForces,tot,fa,1250E,mx,sat
From: https://blog.51cto.com/u_12468613/6384512

相关文章

  • Codeforces Round #594 (Div. 2) 题解
    题目链接:https://codeforces.com/contest/1248 A-IntegerPoints水题#include<bits/stdc++.h>usingnamespacestd;constintmx=1e5+5;typedeflonglongll;inta[mx],b[mx];intmain(){ intt; scanf("%d",&t); while(t--){ intn,m; scan......
  • CodeForcese 1256F [思维]
    题目链接:https://codeforces.com/problemset/problem/1256/F 解题思路:任意的翻转都可以认为是翻转若干个长度为2的,交换两个数主要奇数次翻转。两个串可以翻转成一样,那么一定可以再花费一样的翻转次数变成有序的字符串,连续两个相等的字符翻转任意数次是一样的,所以只要有两个字符......
  • Codeforces Round #599 (Div. 2) 题解
    题目链接:https://codeforces.com/contest/1243 A-MaximumSquare水题不说了#include<bits/stdc++.h>usingnamespacestd;constintmx=1e5+50;typedeflonglongll;intn;inta[mx];intmain(){ intt; scanf("%d",&t); while(t--){ scan......
  • Codeforces #564 (Div. 2) C. Nauuo and Cards[贪心]
    题目链接:http://codeforces.com/contest/1173/problem/C 解题思路:很明显总的抽卡次数是不会超过2*n的。然后我们再将情况分成两种:1.编号1的卡片已经在里面了,并且最底部已经形成了一个1~x的连续的卡片,而且之后x+1,x+2都可以来得及补上,在这种情况下抽卡次数肯定就不会超过n了。2.......
  • Codeforces #564 (Div. 2) D. Nauuo and Circle[树形DP]
    题目链接:http://codeforces.com/contest/1173/problem/D 解题思路:首先得知道按照圆周顺序的话,那么一颗子树必须存放在连续的一段区间里面,现在我们假设根节点是1,那么一颗为u做根节点的子树他的方案数就是各个儿子的方案数的乘积最后再乘以儿子个数+1(u节点本身)的排列方案数。所......
  • Educational Codeforces Round 149 (Rated for Div. 2)
    A.GrasshopperonaLine#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongvoidsolve(){intx,k;cin>>x>>k;if(x%k==0){cout<<"2\n"<<x-1<<"&......
  • Codeforces Round 875 (Div. 2) A-D
    A.TwinPermutations题意:给出一个由[1,2,...,n]组成的数组a,构造另一个由[1,2,...,n]组成的数组b,使得a[1]+b[1]<=a[2]+b[2]<=...<=a[n]+b[n]Solution可以想到只要让他们全为n+1就行了,这样是一定有解的voidsolve(){ intn;cin>>n; for(inti=1;i<=n;i++) { cin>>a[i]; ......
  • Codeforces Round 875 (Div
    CodeforcesRound875(Div.2)C-D题解CProblem-C-Codeforces我们发现题述所形成的父亲节点一定比子节点先画出,并且如果子节点顺序在父节点后面,则父,子节点为同一个周期加入。反之,则子节点的周期为父节点+1。所以做法考虑树上dp,维护第i个节点加入树的周期。转移方程如下:\[......
  • Codeforces Round 875 (Div. 2)
    Preface难得现场打一次,这天下午打了三个半小时的校内赛,然后八点打了两小时ARC,最后再接上两个半小时的CF真是爽歪歪不过有一说一其实很多时候都在坐牢,这场CF也差不多,一个小时写完ABCD然后开始坐牢,其实E基本想出来了但是没想到用随机赋值的方法来实现不过由于这场手很稳因此排名......
  • Codeforces Round 874 (Div. 3)
    A.MusicalPuzzle#include<bits/stdc++.h>usingnamespacestd;voidsolve(){intn;strings;cin>>n>>s;set<string>cnt;for(inti=0;i+1<n;i++)cnt.insert(s.substr(i,2));......