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
");
  return 0;
}

原文地址:https://www.cnblogs.com/juruohx/p/7262690.html