题意:有1~N,n(1e5)个嫌疑人,有m个人说真话,每个人的陈述都形如X是凶手,或X不是凶手。现在给出n,m及n个陈述(以+x/-X表示)要求输出每个人说的话是true ,false or notdefine.
题解:模拟,依次假设每个人是犯人,统计说真话的有几个,如果 ==m 就符合。
现在考虑notdefine:当符合的情况数大于1时,就说明有notdefine。
因为枚举时,某一对-y-x,x是凶手时,-x是假话-y是真话,y是凶手时,-x真话-y假话。而其他人的陈述都与xy无关
所以模拟的方法如下://想法很多。
/*wa
如果一个人说的是+x,那么要么true,要么false。
如果是-x那么如果x是犯人则false,如果不是犯人,可能是true可能是not define(x可能是犯人的情况) .
*/
/*wa的想法:跳过
一个ans[x]数组每次有符合的情况,对每个说真话的人i,ans[i]++,
如果没有多种情况时,根据ans 0,1 情况输出,
否则对于ans>1的输出notdifine
*/
正确逻辑记录任意一个人是凶手时是否满足m句话成立,同时统计成立的情况数def。若def=1,则答案没有notdefine
否则对于+x,x若不可能是凶手(是凶手时不满足条件)puts lie, 若可能是凶手(他是凶手满足条件,同时有多组情况成立。换言之,别人是凶手,也满足条件)puts not define.
//说得很绕,逻辑就是如此。
判断代码如下:
if (cnt == m)def++,ans[x]=1;//def 情况数,ans为i满足条件的记录
if (def != 1)def = 0;
for (int i = 1; i <= n; i++) {
if (a[i] > 0)
if (ans[a[i]] == 0)puts("Lie"); else if (def)puts("Truth"); else puts("Not defined");
else
if (ans[-a[i]] == 0)puts("Truth"); else if (def)puts("Lie"); else puts("Not defined");
}
然后注意记录某人是否可能成为凶手时,O(1)判断,否则会T
具体做法是预处理数组x,y保存 说i是凶手 的人数 ,及否认i是凶手 的人数,再保存一下否认语句的总数k。
然后对于每个i如果x[i]+(k-y[i])==m则他是凶手,
这个公式的具体意思是 当i是凶手时 说i是凶手的个数加上 又没有说i不是凶手的人的个数等于m。。。//真的绕orz
ac代码:
#include<iostream> #define N 100001 #define _for(i, a, b) for (int i = (a); i<(b); ++i) using namespace std; int a[N], x[N], y[N], l[N], t = 0, k = 0; int main() { int n, m; cin >> n >> m; _for(i, 0, n) { cin >> a[i]; if (a[i]>0)x[a[i]]++; else y[-a[i]]++, k++; } _for(i, 1, n + 1) if (x[i] + k - y[i] == m)t++, l[i] = 1; if (t != 1) t = 0; _for(i, 0, n)if (a[i] > 0) cout << (!l[a[i]] ? "Lie" : t ? "Truth" : "Not defined") << endl; else cout << (!l[-a[i]] ? "Truth" : t ? "Lie" : "Not defined") << endl; }