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