NOIP提高组模拟训练18 正确答案(answer)
题目描述:
小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.
时间限制:
1S
空间限制:
256M
solution
当有人满分时或有人0分时
可以发现当有人满分或0分的时候,给出的n个序列中一定有标准答案或标准错误答案,所以我们可以枚举每位神犇的答案,判断一下满分和0分的人数,如果符合就可以直接输出了.
当没有人满分也没有人0分的时候
我们可以用加1算法来暴力枚举出"标准答案",然后判断一下这个"标准答案"符合不符合题目要求,如果符合就输出,否则就把答案改一改,继续判断.
如何判断一个"答案"是否合法
我们在刚开始的时候把所有的字符串全部映射到一个map数组中,然后对于一个字符串.我们看看这个字符串在map里有几个就可以得出与这个字符串一模一样的字符串的个数,然后把这个字符串按位取反,在到
map里面找一找就可以得出以这个"答案"为基准的0分人数. 于是我们就解决了判断答案合法的问题
Code
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<algorithm>
using namespace std;
map<string,int>mp;
string ch[40000];
string c;
int main(){
int n,m,p,q;
scanf("%d%d%d%d",&n,&m,&p,&q);
for (int i=1;i<=n;++i) cin>>ch[i];
sort(ch+1,ch+n+1);
if (p==0&&q!=0){
swap(p,q);
for (int i=1;i<=n;++i) for (int j=0;j<m;++j) if (ch[i][j]=='Y') ch[i][j]='N'; else ch[i][j]='Y';
}
for (int i=1;i<=n;++i) mp[ch[i]]++;
for (int i=1;i<=n;++i)
if (mp[ch[i]]==p){
c=""; for (int j=0;j<m;++j) if (ch[i][j]=='Y') c+='N'; else c+='Y';
if (mp[c]==q){ cout<<ch[i]<<endl; return 0;}
}
if (p==0&&q==0){
c="";for (int i=0;i<m;++i) c+='N';
string c1=""; for (int i=0;i<m;++i) c1+='Y';
while (true){
if (mp[c]==0&&mp[c1]==0){ cout<<c<<endl; return 0;}
int tail=m-1;
while (tail>0&&c[tail]=='Y') --tail;
c[tail]='Y';
for (int i=tail+1;i<m;++i) c[i]='N';
c1="";
for (int i=0;i<m;++i) if (c[i]=='Y') c1+='N';else c1+='Y';
}
}
else printf("-1\n");
return 0;
}