题目大意:
福尔摩斯正在处理一件案子。此时已经抓捕了n个嫌疑人,里面只可能有一个是真正的犯人。福尔摩斯正在审问这些嫌疑人。每个嫌疑人的回答只有两种,一种表明他说编号为i的嫌疑人不是犯人,用-i表示;另一种表明他说编号为i的嫌疑人是犯人,用+i表示。聪明的福尔摩斯已经知道了其中有m个人说的是真话。要求那些人说的是真话,那些人说的是假话。
做法:
这的确是个很有意思的题啊。但是放在这里的话,我们就不能还想以前一样,只用严谨的逻辑推理去得出答案(或者有大牛真的能这样。。。),我们利用计算机的话,就可以暴力的去判断哪些人说的一定是真话,假话,或者不确定。 很简单,我们假设第i号嫌疑人是犯人,那么我们
扫描一遍所有嫌疑人说的话,就可以知道mi个人说了真话,如果mi恰好等于m,那么将i号嫌疑犯记录到ans数组(记录可能为犯人的人的数组)中。当i从0到n扫完之后,如果ans数组里面只有一个元素,那么说明记录的这个嫌疑犯就是真正的犯人,那么就能确定哪些人说的是真话,哪些人说的是假话。 如果ans数组里面有很多元素,那么也能确定哪些人说的一定是真话,哪些人说的是假话,哪些人说的话是不确定的。
这样看来,我们的复杂度是O(n^2)咯?这不超时了吗?。。。难道要重新想方法?。。 其实不用,上文中描红加粗的部分其实不用每次都扫一遍数组,我们可以再输出的时候,维护一个a[i](代表说i是犯人的有多少人),一个b[i](代表说i不是犯人的有多少人)就行,那么前面说的mi就可以这样计算:
mi=a[i]+bn-b[i], 其中bn为说某人不是犯人的人的总数。这样的话,上述遍历的过程就可以变为O(1)时间完成,那这样就可以过啦~
代码:
#include
#include
#define N 100010 using namespace std; int a[N],b[N],ans[N],say[N],numa,numb,numans; int main() { int n,m; scanf("%d%d",&n,&m); for(int i=0;i
0) numa++,a[say[i]]++; else numb++,b[-say[i]]++; } for(int i=1;i<=n;i++) { if(a[i]+numb-b[i]==m) ans[i]=1,numans++; } for(int i=0;i
0 && !ans[say[i]]) cout<<"Lie"<
0 && ans[say[i]] && numans==1) cout<<"Truth"<
0 && ans[say[i]]) cout<<"Not defined"<
缩减版:
#include
const int N=100010;
int n,m,a[N],b[N],as[N],s[N],nb,nans;
int main(){
scanf("%d%d",&n,&m);
for(int i=0;i
0) a[s[i]]++; else nb++,b[-s[i]]++; for(int i=1;i<=n;i++)if(a[i]+nb-b[i]==m) as[i]=1,nans++; nans=nans==1?1:0; for(int i=0;i
0) puts(!as[s[i]]?"Lie":nans?"Truth":"Not defined"); else puts(!as[-s[i]]?"Truth":nans?"Lie":"Not defined"); }