namonamo Daimayuan Online Judge

题目链接:http://oj.daimayuan.top/course/10/problem/678

 

dls 桌面上的两个小女孩除了喜欢亲亲以外,还喜欢一起共用一副耳机听歌。

一天,她们正在听她们最喜欢的歌,一首歌的歌词可以看着一个只包含小写字母的字符串,保证字符串的长度为偶数。

不幸的是,她们的 eirpods 是拼夕夕九块九包邮的,发生了一些神奇的故障,使得对于每个字母,恰好只有一个人能够听到。

在一首歌放完后,她们一边抱怨耳机的质量,同时惊奇地发现,她们两个人所听到的字母各自组成的字符串完全相同

给定一首歌的歌词,判断这种事情是否可能发生。


形式化题意:给定一个长度是偶数,仅有小写字母构成的字符串,判断是否能被分成两个完全相同的子序列。

输入格式

第一行一个正整数 TT,表示数据组数。

接下来每一行一个字符串 SS,表示歌词。

输出格式

输出共 TT 行,每行一个字符串 possible 或 impossible,表示该组数据的答案。

样例输入

5
aabb
abba
namonamo
arqmpfvvbtltlhufznkldkurrazmgebfxeamrewn
aacfcfqqsmksimkoioeertbrtbhphnpnggddjjll

样例输出

possible
impossible
possible
impossible
possible

 思路:如果对整个字符串爆搜的话,每次有两个选择,40个字符串,复杂度为2^40显然超时

那么我们就把他分成两半进行折半搜索,这样复杂度降为2^20大约是1e6,这样就不会超时

那么我们分别搜前半段和后半段,对每个字符要么给a要么给b

然后搜完前后两段之后我们在查一下前面半段的a+后面半段的a==前面半段的b+后面半段的b

例如:

 那么我们可以知道前半段的前缀相等,后半段的后缀相等,前半段多出来的和后半段多出来的中间段相等

那么我们可以对于每次前半段搜到的a,b,先判断前缀是否相等

如果相等,就把中间多出来的用set存一下

然后对于后半段每次搜出来的a,b,先判断他的后缀是否相等

如果相等的话我们就把他的中间段拿出来看看set里有没有,如果有的话就说明符合s1==s2了

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
int gcd(int a,int b) {
	return b? gcd(b,a%b):a;
}
/*
int dx[8]={-2,-2,-1,1,2,2,-1,1};
int dy[8]={-1,1,2,2,1,-1,-2,-2};
int dx[4]={0,-1,0,1};
int dy[4]={-1,0,1,0};
int dx[8]={-1,1,0,0,-1,-1,1,1};
int dy[8]={0,0,-1,1,-1,1,-1,1};
*/
//int e[N],ne[N],h[N],idx,w[N];
/*void add(int a,int b,int c){
	e[idx]=b;
	w[idx]=c;
	ne[idx]=h[a];
	h[a]=idx++;
}
*/
const int N=2e5+10;
int n;
bool f;
set<string> ss;
string s;
void dfs1(int st,int end,string &a,string &b){
	if(f)return ;
	if(st>end){
		for(int i=0;i<min(a.size(),b.size());i++){
			if(a[i]!=b[i])return ;
		}
		if(a.size()<b.size()){
			ss.insert(b.substr(a.size())); 
		}else {
			ss.insert(a.substr(b.size())); 
		}
		return ;
	}
	a.push_back(s[st]);
	dfs1(st+1,end,a,b);
	a.pop_back();
	b.push_back(s[st]);
	dfs1(st+1,end,a,b);
	b.pop_back();
}
void dfs2(int st,int end,string a,string b){
	if(f)return ;
	if(st>end){
		reverse(a.begin(),a.end());
		reverse(b.begin(),b.end());
		for(int i=0;i<min(a.size(),b.size());i++){
			if(a[i]!=b[i])return ;
		}
		string op;
		if(a.size()<b.size()){
			op=b.substr(a.size());
		}else op=a.substr(b.size());
		reverse(op.begin(),op.end());
		if(ss.count(op) ){
			f=true;
			
		}
		return ;
	}
	a.push_back(s[st]);
	dfs2(st+1,end,a,b);
	a.pop_back();
	b.push_back(s[st]);
	dfs2(st+1,end,a,b);
	b.pop_back();	
}
void sove(){
	s.clear();
	ss.clear() ;
	cin>>s;
	f=false;
	n=s.size();
	s="?"+s;
	string a,b;
	dfs1(1,n/2,a,b);
	dfs2(n/2+1,n,a,b);
	if(f)cout<<"possible"<<endl;
	else cout<<"impossible"<<endl;
}

signed main(){
	ios::sync_with_stdio(false);
	cin.tie() ,cout.tie() ;
	int t;
	cin>>t;
	while(t--){
		sove();
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值