PS:我看的别人的博客理解的,比赛的时候没弄出来
PS:转载链接
存在犯罪嫌疑人,当他是实际犯罪者的时候,恰好有且仅有M句话是真话。
那么,如果我们假定一个人是犯罪嫌疑人,有几句话是真话呢?
假设有A句是说xxx是犯罪者的句式,B句是说xxx不是犯罪者的句式。
那么当某人X为犯罪嫌疑人的时候,
真话句数=说X为犯罪者的数量+(B-说X不是犯罪者的数量)//非常自然对吧
然后我们可以得知,哪些人可能是犯罪者了。
如果只有1个人,那么每个人说的话的真假是直接被确定了,毫无疑问。
如果有多个人,
- 如果某人说的是xxx是犯罪者的句式,如果xxx可能为犯罪者,则他的话可真可假;如果xxx不可能是犯罪者,那他说的一定是假话。
- 如果某人说的是xxx不是犯罪者的句式,如果xxx可能为犯罪者,则他的话可真可假;如果xxx不可能是犯罪者,那他说的一定是真话。
所以O(n)统计每个人被指认多少次+每个人被排除嫌疑多少次,O(n)来判断每个人是不是可能是犯罪嫌疑人。最后O(n)推断每句话的真假,没了。
#include <iostream>
#include <string.h>
#include <stdio.h>
#include <algorithm>
#include <limits.h>
#include <math.h>
using namespace std;
const int maxn = 1e5+10;
int ls[maxn];///记录每个人说的信息
int vis[maxn];///记录人是不是可能为犯罪
int va[maxn], vb[maxn];///va记录说第i个人犯罪的个数,vb是说第i个人没有犯罪的人数
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n, m;
scanf("%d%d",&n,&m);
fill(vis,vis+n+1,0);///fill 相当于memeset,但是memsest去清0和-1很好,清其他用fill比较好
fill(va,va+n+1,0);///memset(va,0,(n+1)*sizeof(int);
fill(vb,vb+n+1,0);
int cat = 0, cbt = 0;///cat 是说犯罪的人数,cbt是说没犯罪的人数
for(int i = 1; i <= n; i++)
{
scanf("%d",&ls[i]);
if(ls[i] > 0)
{
cat++;
va[ls[i]]++;
}
else
{
cbt++;
vb[-ls[i]]++;
}
}
int ant = 0;
for(int i = 1; i <= n; i++)
{
int tmp = va[i] + (cbt-vb[i]);///说第i个犯罪人的个数加上说其他人没犯罪的人数
if(tmp == m)///如果恰好等于m的话,说明该人可能犯罪啊
{
ant++;
vis[i] = 1;
}
}
if(ant == 1)///找到一个可能的犯罪的
{
for(int i = 1; i <= n; i++)
{
if(ls[i] > 0)
{
if(vis[ls[i]])///与该人的说法相同
{
puts("Truth");
}
else
puts("Lie");
}
else
{
if(vis[-ls[i]])///和该人的说法相反
{
puts("Lie");
}
else
{
puts("Truth");
}
}
}
}
else///多个人可能是犯罪的
{
for(int i = 1; i <= n; i++)
{
if(ls[i] > 0)
{
if(vis[ls[i]])///该人说他的判断的人犯罪了,没法判断,因为有多个可能的人选
{
puts("Not defined");
}
else///可以清楚的知道该人不是可能的犯罪的,他就说谎了
puts("Lie");
}
else
{
if(vis[-ls[i]])///该人说他的判断的人没有犯罪了,没法判断,因为有多个可能的人选
{
puts("Not defined");
}
else///可以清楚的知道该人不是可能的犯罪的,所以该人说的对
puts("Truth");
}
}
}
}
return 0;
}