loj3501.「聯合省選 2021 A | B」圖函式
阿新 • • 發佈:2021-08-16
我咋覺得這題比 D1T2 不知道簡單到哪裡去了。
考慮這個函式,一個點對 \(i,j(i<j)\) 有貢獻當且僅當 \(i\rightarrow j,j\rightarrow i\) 都只經過 \((i,n]\) 範圍內的點。這是因為如果前面的點對函式有貢獻,那麼他會被刪去,不能經過,否則那個點一定不在和目標點相連的強聯通分量裡面,也不會經過。這個顯然可以 Floyd 做。
接下來考慮刪邊的問題,套路地倒過來變成加邊,顯然答案是單調不降的,我們只要求出每個點最早產生貢獻的時間然後求字首和即可。具體來講我們只需要在跑 Floyd 的時候記錄一下經過的邊的編號的最大值,這個就是他最早產生貢獻的時間。
時間複雜度 \(O(n^3+m)\),時限只有 1s,輕度卡常怎麼 T2T3 都卡,需要在 Floyd 中特判+分類討論減少一些迴圈次數。
#include<iostream> #include<cstdio> using namespace std; int n,m,g[1001][1001],ans[200005]; inline int read() { int x=0; char c=getchar(); while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') { x=(x<<1)+(x<<3)+(c^48); c=getchar(); } return x; } void print(int x) { if(x>=10) print(x/10); putchar(x%10+'0'); } int main() { n=read(),m=read(); for(register int i=1;i<=m;++i) { int x=read(),y=read(); g[x][y]=i; } ans[m+1]=n; for(register int k=n;k;--k) for(register int i=1;i<=n;++i) if(i!=k&&g[i][k]) { if(i<k) { for(register int j=1;j<=n;++j) if(i!=j) g[i][j]=max(g[i][j],min(g[i][k],g[k][j])); } else for(register int j=1;j<k;++j) g[i][j]=max(g[i][j],min(g[i][k],g[k][j])); } for(register int i=1;i<n;++i) for(register int j=i+1;j<=n;++j) if(min(g[i][j],g[j][i])) ++ans[min(g[i][j],g[j][i])]; for(register int i=m;i;--i) ans[i]+=ans[i+1]; for(register int i=1;i<=m+1;++i,putchar(' ')) print(ans[i]); puts(""); return 0; }