woj4765 BestJob

本文深入探讨了字符串匹配算法在特定条件下的应用与优化策略,包括如何通过颜色编码和反串记录来提升搜索效率,以及如何处理不同字符串比较时的边界情况。通过对字符串的预处理和分类讨论,实现了复杂度的有效控制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

无传送门

分类讨论 k 1 k1 k1 k 2 k2 k2的情况。
把相同的字符串染成相同的颜色。
然后还要记一下每个串的反串(每一位取反)。
p o s pos pos记录每种颜色的一个位置。
枚举一下答案是什么再判一下是否可行。
写的时候要想清楚下标是颜色还是字符串标号。

注意 k 1 = 0 , k 2 = 0 k1=0,k2=0 k1=0,k2=0的情况是 u n s i g n e d   l o n g   l o n g unsigned\ long\ long unsigned long long。因为 m ⩽ 50 m \leqslant 50 m50
而且这种情况上界是 2 m 2^m 2m

#include<bits/stdc++.h>
#define ull unsigned long long
#define re register
#define cs const
using namespace std;
cs int N=55;
char s[N][N],rev[N][N],ans[N];
int n,m,k1,k2,flag=0;
int cnt[N],same[N][N];
int col[N],rcol[N],pos[N],tot=0;

inline bool cmp(char *a,char *b){
	for(int re i=1;i<=m;++i)
		if(a[i]!=b[i]) return false;
	return true;
}

inline void update(char *a,char *b){
	bool f=0;
	for(int re i=1;i<=m;++i){
		if(a[i]=='Y'&&b[i]=='N'){f=true;break;}
		if(a[i]=='N'&&b[i]=='Y') return;
	}if(f) for(int re i=1;i<=m;++i) a[i]=b[i];
}
int main(){
//	freopen("bestjob.in","r",stdin);
//	freopen("bestjob.out","w",stdout);
	scanf("%d%d%d%d",&n,&m,&k1,&k2);
	for(int re i=1;i<=m;++i) ans[i]='Y';
	for(int re i=1;i<=n;++i){
		scanf("%s",s[i]+1);
		for(int re j=1;j<=m;++j)
			if(s[i][j]=='Y') rev[i][j]='N';
			else rev[i][j]='Y';
	}
	for(int re i=1;i<=n;++i)
		for(int re j=i+1;j<=n;++j)
			if(cmp(s[i],s[j])) same[i][j]=same[j][i]=1;
	for(int re i=1;i<=n;++i){
		if(!col[i]) col[i]=++tot,pos[tot]=i;
		for(int re j=i+1;j<=n;++j)
			if(same[i][j]) col[j]=col[i];
	}for(int re i=1;i<=n;++i) ++cnt[col[i]];
	for(int re i=1;i<=n;++i)
		for(int re j=1;j<=tot;++j)
			if(cmp(rev[i],s[pos[j]])) rcol[i]=j;
	if(k1&&k2){
		for(int re i=1;i<=tot;++i)
			for(int re j=1;j<=tot;++j) if(i!=j)
				if(cnt[i]==k1&&cnt[j]==k2&&rcol[pos[i]]==j)
						flag=1,update(ans,s[pos[i]]);
		if(flag) for(int re i=1;i<=m;++i) putchar(ans[i]);
		else puts("-1");
		return 0;
	}
	if(k1&&(!k2)){
		for(int re i=1;i<=n;++i)
			if(cnt[col[i]]==k1&&!rcol[i])
				flag=1,update(ans,s[i]);
		if(flag) for(int re i=1;i<=m;++i) putchar(ans[i]);
		else puts("-1");
		return 0;
	}
	if((!k1)&&k2){
		for(int re i=1;i<=n;++i)
			if(cnt[col[i]]==k2&&!rcol[i])
				flag=1,update(ans,rev[i]);
		if(flag) for(int re i=1;i<=m;++i) putchar(ans[i]);
		else puts("-1");
		return 0;
	}
	for(int re i=1;i<=m;++i) ans[i]='N';
	for(ull re state=0;state<(1ull<<m);++state){
		int haha=1;
		for(int re j=1;j<=m;++j)
			if(state&(1ull<<(j-1))) ans[m-j+1]='Y';
			else ans[m-j+1]='N';
		for(int re i=1;i<=n;++i)
			if(cmp(ans,s[i])||cmp(ans,rev[i]))
				{haha=0;break;}
		if(haha){
			for(int re i=1;i<=m;++i)
				putchar(ans[i]);
			return 0;
		}
	}puts("-1");
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值