P9954 [USACO20OPEN] Cowntact Tracing B
首先观察数据范围,发现 \(N\) 和 \(T\) 都很小,那么就可以直接枚举计算答案了。
将几次握手按照时间排序,首先枚举零号病人是哪一只奶牛,再枚举 \(K\) 的值。
如果你把状态设置为 \(0\) 表示没有感染,其他数字表示可以传染的人数,那么需要特别判断一下 \(K\) 为 \(0\) 的情况。
注意每次握手都要将这只奶牛的可传染次数减一。
枚举完成后进行模拟,统计可以作为零号病人的有那几只奶牛,再取 \(K\) 的最小值和最大值即可。
如何判断有无上限?
如果 \(T\) 次可行,那么每一次握手都必定传染,那么加上几次都必定可行,所以若最大值为 \(T\) 时,无上界。
模拟用时 \(O(T+N)\)
代码用时 \(O(NT(N+T))\)
Code
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,t,vis[10005],f[10005],ans,ans2=1e9,ans3,to[10005];
struct P{
int t,x,y;
}a[3005];
bool cmp(P a,P b){
return a.t<b.t;
}
signed main(){
cin>>n>>t;
char c;
for(int i=1;i<=n;i++){
cin>>c;
vis[i]=c-48;
}
for(int i=1;i<=t;i++){
cin>>a[i].t>>a[i].x>>a[i].y;
}
sort(a+1,a+t+1,cmp);
for(int i=1;i<=n;i++){
memset(f,0,sizeof(f));
f[i]=1;
bool fl=false;
for(int k=1;k<=n;k++){
if(f[k]&&!vis[k]||!f[k]&&vis[k]){
fl=true;
break;
}
}
if(!fl){
if(!to[i]){
to[i]=1;
ans++;
}
ans2=min(ans2,0ll);
ans3=max(ans3,0ll);
}
for(int j=1;j<=t;j++){
memset(f,0,sizeof(f));
f[i]=j;
for(int k=1;k<=t;k++){
int x=f[a[k].x],y=f[a[k].y];
if(x>0){
f[a[k].x]--;
if(!f[a[k].x])f[a[k].x]=-1;
if(y==0)f[a[k].y]=j;
}
if(y>0){
f[a[k].y]--;
if(!f[a[k].y])f[a[k].y]=-1;
if(x==0)f[a[k].x]=j;
}
}
bool fl=false;
for(int k=1;k<=n;k++){
if(f[k]&&!vis[k]||!f[k]&&vis[k]){
fl=true;
break;
}
}
if(!fl){
if(!to[i]){
to[i]=1;
ans++;
}
ans2=min(ans2,j);
ans3=max(ans3,j);
}
}
}
cout<<ans<<' '<<ans2;
if(ans3!=t)cout<<' '<<ans3;
else cout<<' '<<"Infinity";
return 0;
}

浙公网安备 33010602011771号