字符串套餐(更新中)

问题 A: 正确答案

题目描述

小H与小Y刚刚参加完UOIP外卡组的初赛,就迫不及待的跑出考场对答案。
“吔,我的答案和你都不一样!”,小Y说道,”我们去找神犇们问答案吧”。
外卡组试卷中共有m道判断题,小H与小Y一共从其他n个神犇那问了答案。之后又从小G那里得知,这n个神犇中有p个考了满分,q个考了零分,其他神犇不为满分或零分。这可让小Y与小H犯了难。你能帮助他们还原出标准答案吗?如有多解则输出字典序最小的那个。无解输出-1。

输入

第一行四个整数n, m, p, q,意义如上描述。
接下来n行,每一行m个字符’N’或’Y’,表示这题这个神犇的答案。

输出

仅一行,一个长度为m的字符串或是-1。

样例输入

2 2 2 0
YY
YY

样例输出

YY

提示

30% : n <= 100.
60% : n <= 5000 , m <= 100.
100% : 1 <= n <= 30000 , 1 <= m <= 500. 0 <= p , q 且 p + q <= n.

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<cstdlib>
#include<algorithm>
using namespace std;
int n,m,p,q;
char fuck[501];
string a[30010],ans;
map<string,int> mp;
bool flag;
bool cmp(string a,string b)
{
    return a<b;
}
bool check(string s)
{
    string ss;
    for(int i=0;i<m;i++)
    {   
        if(s[i]=='N') ss+='Y';
        else ss+='N';
    }
    if(mp.find(ss)==mp.end()) return 1;
    return 0;
}
void dfs(string s,int dep)
{
    if(flag) return;
    if(dep==m) 
    {
        if(!mp[s]&&check(s))
        {   
            flag=1;
            ans=s;
        }
        return;
    }
    dfs(s+'N',dep+1);
    dfs(s+'Y',dep+1);
}
int main()
{   
    scanf("%d%d%d%d",&n,&m,&p,&q);
    for(int i=1;i<=n;i++)
    {   
        scanf("%s",fuck);
		a[i]=string(fuck);
		mp[a[i]]++;
    }
    if(p==0&&q==0)
    {
        dfs("N",1);
        if(!flag) dfs("Y",1);
        if(!flag) 
        {
            puts("-1");
        }
        else cout<<ans;
    }
    else
    {
		bool ff=0;
		if(p==0) 
		{
			swap(p,q);ff=1;
		}
        sort(a+1,a+1+n,cmp);
        for(int i=1;i<=n;i++)
        {   
            string s;
            if(mp[a[i]]==p) 
            {
                for(int j=0;j<m;j++)
                {   
                    if(a[i][j]=='N') s+='Y';
                    else s+='N';
                }
                if(mp[s]==q) 
                {
					if(ff)
					{
						for(int j=0;j<m;j++)
						{
							if(a[i][j]=='N') cout<<'Y';
							else cout<<'N';
						}
					}
                    else ans=a[i];
					flag=1;break;
                }
            }
        }
        if(!flag) puts("-1");
        else cout<<ans;
    }
}

问题 B: 无名

题目描述

题意很简单,给你一个串,求他有多少个不同的子串,满足前缀为A,后缀为B。
需要注意的是,串中所有的字母都是小写字母。
友情提示:如果你过不了样例,请注意是 不同 的子串。

输入

第一行母串S;
第二行串A;
第三行串B。

输出

一个数,即有多少不同的子串。

样例输入

abababab
a
b

样例输出

4

提示

100%:
length(S)<=2000;
length(A)<=2000;
length(B)<=2000;
30%:都少个0。

#include<bits/stdc++.h>
using namespace std;
const int sed=131;
unsigned long long ha[2002],q[2002]={1};
int len,lena,lenb,tot1,tot2,ans;
int aa[2002],bb[2002];
string s,a,b,fff[2002];
set<unsigned long long> S;
int main()
{	
    cin>>s>>a>>b;
    len=s.size();lena=a.size();lenb=b.size();
    for(int i=0;i<len-lena+1;i++)
    {	
        bool flag=0;
        for(int j=0;j<lena;j++)
        {
            if(s[i+j]!=a[j]) {flag=1;break;}
        }
        if(!flag) aa[++tot1]=i+lena-1;
    }
    for(int i=0;i<len-lenb+1;i++)
    {
        bool flag=0;
        for(int j=0;j<lenb;j++)
        {
            if(s[i+j]!=b[j]) {flag=1;break;}
        }
        if(!flag) bb[++tot2]=i;
    }
    ha[0]=s[0]-'0';
    for(int i=1;i<len;i++)
    {
        ha[i]=ha[i-1]*sed+s[i]-'0';
        q[i]=q[i-1]*sed;
    }
    for(int i=1;i<=tot1;i++)
        for(int j=1;j<=tot2;j++)
        {
            if(aa[i]>bb[j]+lenb-1||aa[i]-lena+1>bb[j]) continue;
            else 
            {               
                unsigned long long k1=ha[aa[i]-lena]*q[bb[j]+lenb-1-aa[i]+lena]-ha[bb[j]+lenb-1];
                unsigned long long k2=ha[bb[j]+lenb-1]-ha[aa[i]-lena]*q[bb[j]+lenb-1-aa[i]+lena];
                S.insert(max(k1,k2));
            }
        }
    ans=S.size();
    printf("%d",ans);
}

问题 C: Friends

题目描述

有三个好朋友喜欢在一起玩游戏,A君写下一个字符串S,B君将其复制一遍得到T,C君在T的任意位置(包括首尾)插入一个字符得到U.现在你得到了U,请你找出S.

输入

第一行一个数N,表示U的长度.
第二行一个字符串U,保证U由大写字母组成.

输出

若S不存在,输出"NOT POSSIBLE".若S不唯一,输出"NOT UNIQUE".否则输出S.

样例输入

7
ABXCABC

样例输出

ABC

提示

Sample Input2:
6
ABCDEF
Sample Input3:
9
ABABABABA

Sample Output2:
NOT POSSIBLE
Sample Output3:
NOT UNIQUE

对于100%的数据 2<=N<=2000001

#include<bits/stdc++.h>
using namespace std;
int n,ans,sum;
char s[2000010];
unsigned long long ha[2000010],q[2000010]={1},k1,k2;
const int sed=131;
set<unsigned long long> S;
int main()
{
	scanf("%d%s",&n,s+1);
	for(int i=1;i<=n;i++)
	{	
		ha[i]=ha[i-1]*sed+s[i]-'0';
		q[i]=q[i-1]*sed;
	}
	int mid=(n-1)/2;
	for(int i=1;i<=n;i++)
	{
		if(i<=mid) 
		{	
			k1=ha[i-1]*q[mid+1-i]+(ha[mid+1]-ha[i]*q[mid+1-i]);
			k2=ha[n]-ha[mid+1]*q[mid];
		}
		if(i>mid)
		{
			k1=ha[mid];
			k2=(ha[i-1]-ha[mid]*q[i-mid-1])*q[n-i]+ha[n]-ha[i]*q[n-i];
		}
		if(k1==k2) ans=i,S.insert(k1);
	}
	sum=S.size();
	if(sum==0) puts("NOT POSSIBLE");
	else if(sum>1) puts("NOT UNIQUE");
	else 
	{
		string ss;
		if(ans<=mid) 
		{
			for(int i=1;i<=mid+1;i++)
				if(i!=ans) ss+=s[i];
			cout<<ss<<endl;
		}
		else 
		{
			for(int i=mid+1;i<=n;i++)
				if(i!=ans) ss+=s[i];
			cout<<ss<<endl;
		}
	}
	return 0;
}

问题 D: Antisymmetry

题目描述

对于一个01字符串,如果将这个字符串0和1取反后,再将整个串反过来和原串一样,就称作“反对称”字符串。比如00001111和010101就是反对称的,1001就不是。
现在给出一个长度为N的01字符串,求它有多少个子串是反对称的。

输入

第一行一个正整数N (N ≤500,000)。第二行一个长度为N的01字符串。

输出

一个正整数,表示反对称子串的个数。

样例输入

8
11001011

样例输出

7

#include<bits/stdc++.h>
using namespace std;
const int sed=131;
int n,ans;
unsigned long long ha1[500010],ha2[500010],q[500010]={1};
char s[500010];
bool check(int len,int x)
{
	unsigned long long k1,k2;
	k1=ha1[x]-ha1[x-len]*q[len];
	k2=ha2[x+1]-ha2[x+len+1]*q[len];
	return k1==k2;
}
int main()
{
	scanf("%d%s",&n,s+1);
	for(int i=1;i<=n;i++)
	{
		ha1[i]=ha1[i-1]*sed+s[i]-'0';
		q[i]=q[i-1]*sed;
	}
	for(int i=n;i>=1;i--)
	{
		ha2[i]=ha2[i+1]*sed+((s[i]-'0')^1);
	}
	for(int i=1;i<=n;i++)
	{
		int l=1,r=min(i,n-i),mid,tot=0;
		while(l<=r) 
		{
			mid=(l+r)>>1;
			if(check(mid,i)) l=mid+1,tot=mid;
			else r=mid-1;
		}
		ans+=tot;
	}
	printf("%d",ans);
	return 0;
}
posted @ 2018-08-28 21:23  Drury  阅读(270)  评论(0编辑  收藏  举报