CF1704E Count Seconds
E. Count Seconds
赛时绝杀了(((
我们算一下出度为 \(0\) 的节点 \(t\) 所需要排出多少次 \(1\)。通过简单的拓扑可以算出来,这非常简单。问题出在并不是时时刻刻这个节点上又有数字,那么就会造成耽搁,使得时间变长。那么有多少时间是耽搁的呢?
我们假设 \(dis_u\) 表示节点 \(u\) 到 \(t\) 的最短距离。那么令 \(D=\max\limits_{i=1}^n {dis_u}\ \ a_u>0\)。耽搁的时间一定在 \(1\) 到 \(D\) 之间。因为在时刻 \(D\) 之后,\(t\) 就会一直工作直到结束。这很好理解。\(D\leq m\),因此我们直接模拟即可。时间复杂度 \(O(m+m^2)\)。
//Don't act like a loser.
//This code is written by huayucaiji
//You can only use the code for studying or finding mistakes
//Or,you'll be punished by Sakyamuni!!!
#include<bits/stdc++.h>
#define int long long
using namespace std;
int read() {
char ch=getchar();
int f=1,x=0;
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return f*x;
}
char read_char() {
char ch=getchar();
while(!isalpha(ch)) {
ch=getchar();
}
return ch;
}
const int MAXN=1000+10,MOD=998244353;
int n,cnt,pp,m;
int a[MAXN],h[MAXN],ind[MAXN],oud[MAXN],f[MAXN],b[MAXN];
queue<int> q;
struct edge {
int v,nxt;
}e[MAXN<<1];
void addedge(int u,int v) {
e[++cnt].v=v;
e[cnt].nxt=h[u];
h[u]=cnt;
}
void topu() {
for(int i=1;i<=n;i++) {
if(!ind[i]) {
q.push(i);
}
}
while(!q.empty()) {
int u=q.front();
q.pop();
for(int i=h[u];i;i=e[i].nxt) {
int v=e[i].v;
f[v]+=f[u];
f[v]%=MOD;
ind[v]--;
if(!ind[v]) {
q.push(v);
}
}
}
}
signed main() {
int t=read();
while(t--) {
cin>>n>>m;
fill(h+1,h+n+1,0);
fill(oud+1,oud+n+1,0);
fill(ind+1,ind+n+1,0);
cnt=0;
for(int i=1;i<=n;i++) {
f[i]=a[i]=b[i]=read();
}
for(int i=1;i<=m;i++) {
int u,v;
u=read();v=read();
addedge(u,v);
ind[v]++;
oud[u]++;
}
for(int i=1;i<=n;i++) {
if(!oud[i]) {
pp=i;
}
}
topu();
int cnt=0;
for(int tm=1;tm<=m;tm++) {
bool ok=0;
for(int i=1;i<=n;i++) {
a[i]=b[i];
if(b[i]) {
b[i]--;
ok=1;
}
}
if(!ok) {
break;
}
if(!a[pp]) {
cnt++;
}
for(int u=1;u<=n;u++) {
if(!a[u]) {
continue;
}
a[u]--;
for(int i=h[u];i;i=e[i].nxt) {
int v=e[i].v;
b[v]++;
}
}
}
int ans=f[pp]+cnt;
ans=(ans+MOD)%MOD;
cout<<ans<<endl;
}
return 0;
}