正确答案 全国信息学奥林匹克联赛( ( NOIP2014) 复 赛 模拟题 Day1 长乐一中

【题目描述】
小 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.

長樂一中給出的解析:

30%: O(n ^ 2 * m)暴力判断。
100%: 很显然答案的可能性最多只有 n 种,所以我们将所有人的答案按字典序排序后枚举
将每个人的答案作为正确答案来进行判断。 由于是判断题, 若当前人的答案为正确答
案则零分者的答案也就确定了, 那么只需统计出这两种答案的人数判断是否满足题意
即可。这一步使用字符串哈希即可解决。
另外要注意 p = 0 和 p = q = 0 的情况。

長樂一中給出的正解代碼:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <cstring>
  4 #include <cstdio>
  5 #include <cmath>
  6 using namespace std;
  7 
  8 const int N = 3e4 + 2, M = 5e2 + 2, sed = 31, SED = 131, mod = 70177, MOD = 92311;
  9 int n, m, p, q, ans, hash[N], HASH[N];
 10 int top, info[mod], nxt[N * 2], fet[N * 2], cnt[N * 2];
 11 struct node {
 12 char s[M];
 13 inline bool operator < (const node &b) const {
 14 return strcmp(s, b.s) < 0;
 15 }
 16 } a[N];
 17 
 18 inline void Insert(const int &x, const int &y) {
 19 for (int k = info[x]; k; k = nxt[k])
 20 if (fet[k] == y) {
 21 ++cnt[k]; return ;
 22 }
 23 nxt[++top] = info[x]; info[x] = top;
 24 fet[top] = y; cnt[top] = 1;
 25 return ;
 26 }
 27 
 28 inline int Query(const int &x, const int &y) {
 29 for (int k = info[x]; k; k = nxt[k])
 30 if (fet[k] == y) return cnt[k];
 31 return 0;
 32 }
 33 
 34 inline void Solve1() {
 35 int tmp, TMP; ans = -1;
 36 for (int i = 0; i < n; ++i) {
 37 tmp = TMP = 0;
 38 for (int j = 0; j < m; ++j) {
 39 tmp = (tmp * sed + (a[i].s[j] == 'N')) % mod;
 40 TMP = (TMP * SED + (a[i].s[j] == 'N')) % MOD;
 41 }
 42 hash[i] = tmp, HASH[i] = TMP;
 43 Insert(tmp, TMP);
 44 }
 45 for (int i = 0; i < n; ++i)
 46 if (Query(hash[i], HASH[i]) == p) {
 47 tmp = TMP = 0;
 48 for (int j = 0; j < m; ++j) {
 49 tmp = (tmp * sed + (a[i].s[j] == 'Y')) % mod;
 50 TMP = (TMP * SED + (a[i].s[j] == 'Y')) % MOD;
 51 }
 52 if (Query(tmp, TMP) == q) {
 53 ans = i; break;
 54 }
 55 }
 56 if (ans != -1) printf("%s
", a[ans].s);
 57 else puts("-1");
 58 return ;
 59 }
 60 
 61 char cur[M];
 62 inline void Solve2() {
 63 int tmp, TMP; ans = -1;
 64 for (int i = 0; i < n; ++i) {
 65 tmp = TMP = 0;
 66 for (int j = 0; j < m; ++j) {
 67 tmp = (tmp * sed + (a[i].s[j] == 'N')) % mod;
 68 TMP = (TMP * SED + (a[i].s[j] == 'N')) % MOD;
 69 }
 70 hash[i] = tmp, HASH[i] = TMP;
 71 Insert(tmp, TMP);
 72 }
 73 for (int i = n - 1; i >= 0; --i)
 74 if (Query(hash[i], HASH[i]) == q) {
 75 tmp = TMP = 0;
 76 for (int j = 0; j < m; ++j) {
 77 tmp = (tmp * sed + (a[i].s[j] == 'Y')) % mod;
 78 TMP = (TMP * SED + (a[i].s[j] == 'Y')) % MOD;
 79 }
 80 if (Query(tmp, TMP) == p) {
 81 ans = i; break;
 82 }
 83 }
 84 if (ans != -1) {
 85 for (int i = 0; i < m; ++i)
 86 cur[i] = a[ans].s[i] == 'N' ? 'Y' : 'N';
 87 printf("%s
", cur);
 88 }
 89 else puts("-1");
 90 return ;
 91 }
 92 
 93 void Solve3() {
 94 int tmp, TMP;
 95 for (int i = 0; i < n; ++i) {
 96 tmp = TMP = 0;
 97 for (int j = 0; j < m; ++j) {
 98 tmp = (tmp * sed + (a[i].s[j] == 'N')) % mod;
 99 TMP = (TMP * SED + (a[i].s[j] == 'N')) % MOD;
100 }
101 Insert(tmp, TMP);
102 tmp = TMP = 0;
103 for (int j = 0; j < m; ++j) {
104 tmp = (tmp * sed + (a[i].s[j] == 'Y')) % mod;
105 TMP = (TMP * SED + (a[i].s[j] == 'Y')) % MOD;
106 }
107 Insert(tmp, TMP);
108 }
109 bool flag = true;
110 for (int i = 0; i < m; ++i) cur[i] = 'N';
111 do {
112 tmp = TMP = 0;
113 for (int j = 0; j < m; ++j) {
114 tmp = (tmp * sed + (cur[j] == 'N')) % mod;
115 TMP = (TMP * SED + (cur[j] == 'N')) % MOD;
116 }
117 if (Query(tmp, TMP) == 0) {
118 flag = true; break;
119 }
120 flag = false;
121 for (int j = m - 1; j >= 0; --j)
122 if (cur[j] == 'Y') cur[j] = 'N';
123 else {
124 cur[j] = 'Y'; flag = true; break;
125 }
126 } while (flag);
127 if (flag) printf("%s
", cur);
128 else puts("-1");
129 return ;
130 }
131 
132 int main() {
133 freopen("answer.in", "r", stdin);
134 freopen("answer.out", "w", stdout);
135 scanf("%d%d%d%d", &n, &m, &p, &q);
136 for (int i = 0; i < n; ++i) scanf("%s", a[i].s);
137 sort(a, a + n);
138 if (p) Solve1();
139 else if (q) Solve2();
140 else Solve3();
141 fclose(stdin); fclose(stdout);
142 return 0;
143 }
View Code

代碼實現:

#include<map>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,m,p,q,a,z=1;
char ch[500],cn[500];
string st[30000];//儲存每個答案。 
map <string,int> mm;//儲存每種答案出現的次數。 
void part_1(){
for(int i=0;i<n;i++){//順序枚舉。 
if(mm[st[i]]==p){ //假如當前答案的出現數等於正解數, 
for(int j=0;j<m;j++){//ch中是這個答案的錯排。 
if(st[i][j]=='N') ch[j]='Y';
else ch[j]='N';
}
if(mm[ch]==q){cout<<st[i]<<endl;return;}//並且它的錯排的出現數等於報零答案數,可以認為這是正解。 
}
}
printf("-1
");//如果沒有找到,即p,q不合法,輸出負一。 
}
void part_2(){
for(int i=0;i<n;i++){
if(mm[st[i]]==q){//如果當前答案的出現數等於報零答案數, 
for(int j=0;j<m;j++){
if(st[i][j]=='N') ch[j]='Y';
else ch[j]='N';
}
if(!mm[cn]){cout<<ch<<endl;return;}//並且它的錯排,即正解,沒有出現過,則它的錯排合法。
}
}
printf("-1
");//對於數據,並無意義。 
}
void part_3(){//正解和報零答案都沒有出現過,所以要捋一下全排列。 
for(int i=0;i<m;i++){
cn[i]='N';//從字典序排列時最前面的先拿出。 
z*=2;//z等於二的m次冪。 
}
for(int i=0;i<z/2;i++){//小於z可以理解,因為這是一個類似01字串的字符串。 
a=m-1;cn[a]+='Y'-'N';
while(cn[a]==2*'Y'-'N'&&a>0){
cn[a--]='N';
cn[a]+='Y'-'N';
}//因為有錯排,所以是小於z/2。 
for(int j=0;j<m;j++){
if(cn[j]=='N') ch[j]='Y';
else ch[j]='N';
}
if(!mm[cn]&&!mm[ch]){cout<<cn<<endl;return;}//如果該排列即其錯排都為出現個,則該排列合法。 
}
printf("-1
");//對於數據,並無意義。 
}
int main(){
freopen("answer.in","r",stdin);
freopen("answer.out","w",stdout);
scanf("%d%d%d%d",&n,&m,&p,&q);
for(int i=0;i<n;i++){
scanf("%s",&ch);//一種比較簡單的讀入技巧,時間大概是直接cin流輸入的三分之一。 
for(int j=0;j<m;j++) st[i]+=ch[j];
++mm[st[i]];//記錄重新次數。 
}
sort(st,st+n);//因為答案要按字典序輸出,所以排一下序。 
if(p) part_1();
if(!p&&q) part_2();
if(!p&&!q) part_3();
return 0;
}
View Code

吐槽一下,這個答案很多時候并並不正確。

原文地址:https://www.cnblogs.com/J-william/p/6062585.html