思路:分析题意知给定的图一定是一个有向无环图,所以能够使用拓扑序,在进行拓扑排序的途中统计一个维护一个完成当前任务的最小时间,那么入度为零的点就是一开始的时间,其他的点就是统计所有前驱的最大值max,表示至少在这个最大值之后它才能够完成这个任务,然后我们在看一下max%k与w[u]的关系,如果是大于关系,则代表要完成w[u]必须要到下一天了,因为这一天已经是max%k了,已经比w[u]大了;如果是小于关系,那么能够在这一天完成这个任务。那么我们现在就得到了每个点能够完成的最小的时间,那么统计最大值以及最小值相减就是答案吗?不是的,因为我们通过样例能够发现,我们可以讲某个入度为零的点延后一天完成,这样就使得最小值变大了,但是可能最大值会增加一点点,这样就能够使得差值变小了,那么我们能否枚举所有的入度为零的点,从小到达枚举,然后讲它们延后一天,统计出延后之后的最大值,然后减去最小值呢?这样做是可以的,我们发现每个点最多只会被延后一天(因为假如说u为当前的点,j为其前驱节点,那么如果其中某个j延后了一天,对于u来说,有两种情况,如果延后一天之后也不比它大,说明我u不用延后保持原来的即可,如果延后之后比它大了,说明我必须要延后一天了。但是出现了第二中状态以后,就不会再出现第二种状态了,因为原先u的完成时间是比所有的j都大的,那么如果u+k,那么对于所有的j来说,j+k一定也不会比u+k大了,所有一定是满足条件了,所以每个点最多只会被延后一天,所以每个节点最多只会被遍历一次),那么这样我们就能够保证修改的时间复杂度了,所以就可以直接暴力枚举了
- // Problem: E. Speedrun
- // Contest: Codeforces - Pinely Round 2 (Div. 1 + Div. 2)
- // URL: https://codeforces.com/contest/1863/problem/E
- // Memory Limit: 256 MB
- // Time Limit: 2000 ms
-
- #include
- #include
- #include
- #define fi first
- #define se second
- #define i128 __int128
- using namespace std;
- typedef long long ll;
- typedef double db;
- typedef pair<int,int> PII;
- const double eps=1e-7;
- const int N=5e5+7 ,M=5e5+7, INF=0x3f3f3f3f,mod=1e9+7,mod1=998244353;
- const long long int llINF=0x3f3f3f3f3f3f3f3f;
- inline ll read() {ll x=0,f=1;char c=getchar();while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
- while(c>='0'&&c<='9') {x=(ll)x*10+c-'0';c=getchar();} return x*f;}
- inline void write(ll x) {if(x < 0) {putchar('-'); x = -x;}if(x >= 10) write(x / 10);putchar(x % 10 + '0');}
- inline void write(ll x,char ch) {write(x);putchar(ch);}
- void stin() {freopen("in_put.txt","r",stdin);freopen("my_out_put.txt","w",stdout);}
- bool cmp0(int a,int b) {return a>b;}
- template<typename T> T gcd(T a,T b) {return b==0?a:gcd(b,a%b);}
- template<typename T> T lcm(T a,T b) {return a*b/gcd(a,b);}
- void hack() {printf("\n----------------------------------\n");}
-
- int T,hackT;
- int n,m,k;
- int w[N];
- int h[N],e[M],ne[M],idx;
- ll dist[N];
- int din[N];
- vector<int> son[N];
- ll maxn=-1;
-
- void add(int a,int b) {
- e[idx]=b,ne[idx]=h[a],h[a]=idx++;
- }
-
- void topsort() {
- queue<int> q;
- for(int i=1;i<=n;i++) {
- if(!din[i]) q.push(i);
- }
-
- while(q.size()) {
- auto it=q.front();
- q.pop();
-
- if(son[it].size()==0) dist[it]=w[it];
- else {
- ll sum=0;
-
- for(int i=0;i
size();i++) { - int j=son[it][i];
-
- sum=max(sum,dist[j]);
- }
-
- if((sum%k)<=w[it]) sum+=w[it]-(sum%k);
- else sum+=k-(sum%k)+w[it];
-
- dist[it]=sum;
- }
-
-
- for(int i=h[it];i!=-1;i=ne[i]) {
- int j=e[i];
-
- din[j]--;
- if(din[j]==0) q.push(j);
- }
- }
- }
-
- void dfs(int u,ll &maxn) {
- dist[u]=dist[u]+k;
- maxn=max(maxn,dist[u]);
- for(int i=h[u];i!=-1;i=ne[i]) {
- int j=e[i];
-
- if(dist[j]>=dist[u]) continue;
- else dfs(j,maxn);
- }
- }
-
- void solve() {
- n=read(),m=read(),k=read();
-
- memset(h,-1,sizeof(int)*(n+4));
- memset(din,0,sizeof(int)*(n+4));
- idx=0;
- for(int i=1;i<=n;i++) w[i]=read(),son[i].clear(),dist[i]=0;
-
- maxn=-1;
- while(m--) {
- int a=read(),b=read();
- add(a,b);
- son[b].push_back(a);
- din[b]++;
- }
-
- vector<int> vis;
- for(int i=1;i<=n;i++) if(!din[i]) vis.push_back(i);
-
- topsort();
-
- for(int i=1;i<=n;i++) maxn=max(maxn,dist[i]);
-
- sort(vis.begin(),vis.end(),[&](int &a,int &b){
- return w[a]
- });
-
- ll res=llINF;
- res=min(res,maxn-dist[vis[0]]);
-
- for(int i=0;i
size()-1;i++) { - dfs(vis[i],maxn);
- res=min(res,maxn-dist[vis[i+1]]);
- }
-
- printf("%lld\n",res);
- }
-
- int main() {
- // init();
- // stin();
- // ios::sync_with_stdio(false);
-
- scanf("%d",&T);
- // T=1;
- while(T--) hackT++,solve();
-
- return 0;
- }