NOIP2024 RP++.|

一位XXS

园龄:5个月粉丝:1关注:1

洛谷P1039 [NOIP2003 提高组] 侦探推理

Problem


Solve

较为快速且好想的暴力方法是枚举m个人中选n个的组合方案,然后对证词进行检验,时间复杂度\(O(\frac{m!}{n!^2}p)\),仔细算算竟然能够在2e8左右通过
但实际上这道题在当年肯定是给不了你2e8/sec的算力的,这道题目能够评蓝我觉得上面方法肯定是不配的
结合€€£在18年及以前的4e6/sec祖传老爷机,我们需要换一种方法。
可以观察到,我们在枚举组合的时候往往因为一个小小的改动而重新枚举p,这样肯定不优,我们可以换种角度:
每次枚举真相可能的结果,将结果代入证词进行检验,计算一下在这种情况有多少人说假话即可,时间复杂度\(O(dnp)\),d是星期的总数,为7
这样就能过掉了,感觉根本没有蓝的难度。
PS:其实还有一种方法能把d优化掉,但是很麻烦,不建议写(直接枚举凶手,根据初步得到的嫌疑人信息推理可能的星期)

Code

#include<bits/stdc++.h>
using namespace std;
int n,m,p,w[105],f[105];//0:UB 1~7:Monday~Sunday 8/9: 2idx/2idx+1:
string name[25],ans;
map<string,int> b,day;
void init(){
day["Monday."]=1,day["Tuesday."]=2,day["Wednesday."]=3,day["Thursday."]=4;
day["Friday."]=5,day["Saturday."]=6,day["Sunday."]=7;
}
int main(){
init();
cin>>n>>m>>p;
for(int i=1;i<=n;i++){
cin>>name[i];
b[name[i]]=i;
}
string tmp,t,word[255];
int cnt=0;
getline(cin,t);
for(int i=1;i<=p;i++){
getline(cin,t);
t.erase(t.size()-1,1);//The problem's case was made in windows
tmp="",t+=" ";
cnt=0;
for(int j=0;j<t.size();j++){
if(t[j]!=' ')tmp+=t[j];
else{
word[++cnt]=tmp;
tmp="";
}
}
w[i]=b[word[1].substr(0,word[1].size()-1)];
if(cnt==4){
if(word[2]=="I"&&word[3]=="am"&&word[4]=="guilty."){
f[i]=8;
}
if(word[3]=="is"&&word[4]=="guilty."){
f[i]=10*b[word[2]];
}
if(word[2]=="Today"&&word[3]=="is"){
f[i]=day[word[4]];
}
}else if(cnt==5){
if(word[2]=="I"&&word[3]=="am"&&word[4]=="not"&&word[5]=="guilty."){
f[i]=9;
}
if(word[3]=="is"&&word[4]=="not"&&word[5]=="guilty."){
f[i]=10*b[word[2]]+1;
}
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=7;j++){
int cntf=0,cnth=0,c[25];
memset(c,0,sizeof(c));
for(int k=1;k<=p;k++){
if(!f[k])continue;
if(f[k]==j||f[k]==i*10||f[k]==8&&w[k]==i||f[k]==9&&w[k]!=i||f[k]>=10&&f[k]%10==1&&f[k]/10!=i){
if(c[w[k]]==-1){
cntf=0x3f3f3f3f;
break;
}
if(c[w[k]]==1){
continue;
}
cnth++;
c[w[k]]=1;
}else{
if(c[w[k]]==1){
cntf=0x3f3f3f3f;
break;
}
if(c[w[k]]==-1){
continue;
}
cntf++;
c[w[k]]=-1;
}
}
if(cntf<=m&&cntf+(n-cnth-cntf)>=m){
if(ans==""){
ans=name[i];
break;
}else{
cout<<"Cannot Determine";
return 0;
}
}
}
}
if(ans=="")cout<<"Impossible";
else cout<<ans;
return 0;
}

本文作者:yiweixxs

本文链接:https://www.cnblogs.com/yiweixxs/p/18582893

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   一位XXS  阅读(31)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起