问题 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;
}