断案

http://codeforces.com/problemset/problem/156/B

题目大意:

福尔摩斯正在处理一件案子。此时已经抓捕了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)时间完成,那这样就可以过啦~

代码:
[cpp]  view plain  copy
  1. #include <iostream>  
  2. #include <cstdio>  
  3. #define N 100010  
  4. using namespace std;  
  5. int a[N],b[N],ans[N],say[N],numa,numb,numans;  
  6. int main()  
  7. {  
  8.     int n,m;  
  9.     scanf("%d%d",&n,&m);  
  10.     for(int i=0;i<n;i++)  
  11.     {  
  12.         scanf("%d",&say[i]);  
  13.         if(say[i]>0) numa++,a[say[i]]++;  
  14.         else numb++,b[-say[i]]++;  
  15.     }  
  16.     for(int i=1;i<=n;i++)  
  17.     {  
  18.         if(a[i]+numb-b[i]==m) ans[i]=1,numans++;  
  19.     }  
  20.     for(int i=0;i<n;i++)  
  21.     {  
  22.         if(say[i]>0 && !ans[say[i]]) cout<<"Lie"<<endl;  
  23.         else if(say[i]>0 && ans[say[i]] && numans==1) cout<<"Truth"<<endl;  
  24.         else if(say[i]>0 && ans[say[i]]) cout<<"Not defined"<<endl;  
  25.         else if(say[i]<0 && ans[-say[i]] && numans==1) cout<<"Lie"<<endl;  
  26.         else if(say[i]<0 && ans[-say[i]]) cout<<"Not defined"<<endl;  
  27.         else if(say[i]<0 && !ans[-say[i]]) cout<<"Truth"<<endl;  
  28.     }  
  29.     return 0;  
  30. }  



缩减版:
[cpp]  view plain  copy
  1. #include <cstdio>  
  2. const int N=100010;  
  3. int n,m,a[N],b[N],as[N],s[N],nb,nans;  
  4. int main(){  
  5.     scanf("%d%d",&n,&m);  
  6.     for(int i=0;i<n&&~scanf("%d",&s[i]);i++)  
  7.         if(s[i]>0) a[s[i]]++;  
  8.         else nb++,b[-s[i]]++;  
  9.     for(int i=1;i<=n;i++)if(a[i]+nb-b[i]==m) as[i]=1,nans++;  
  10.     nans=nans==1?1:0;  
  11.     for(int i=0;i<n;i++)  
  12.         if(s[i]>0) puts(!as[s[i]]?"Lie":nans?"Truth":"Not defined");  
  13.         else puts(!as[-s[i]]?"Truth":nans?"Lie":"Not defined");  
  14. }  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值