洛谷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;
}

posted @ 2024-12-02 22:27  一位XXS  阅读(115)  评论(0)    收藏  举报