《陝西師範大學第九屆ACM程式設計競賽》
阿新 • • 發佈:2020-08-17
A:其實並不是特別難的一個題,想的太複雜了。
首先,我們把關係看成能夠傳遞的,那麼我們並查集統計連通塊之後。
可以發現,對於一個連通塊,最優方案肯定只有1個人會沒朋友。
因為一直把和當前刪的點有關係的人的人刪進去,最後肯定就能刪完全部點,並且保證只有第一個進去的人沒朋友。
因為要保證字典序最小,我們每次合併並查集的時候,都讓大的以小的為父節點,那麼最後這個集合的根,肯定就是這個集合裡最小的點。
那麼我們先把根都扔到小頂堆裡,然後在把和堆頂相鄰的沒刪的元素放入,因為小頂堆,會自己保證最小字典序。
// Author: levil #pragma GCC optimize(2) #pragma GCC optimize(3) #includeView Code<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double ld; typedef pair<int,int> pii; const int N = 1e6+5; const int M = 1e4; const LL Mod = 998244353; #define rg register #define pi acos(-1) #define INF 1e9 #define INM INT_MIN #define dbg(ax) cout << "now this num is " << ax << endl; namespaceFASTIO{ /*const int BUF_SIZE = 8e7; inline char nc(){ static char buf[BUF_SIZE],*p1 = buf,*p2 = buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,BUF_SIZE,stdin),p1==p2)?EOF:*p1++; }*///file close. inline int read(){ int x = 0,f = 1;char c = getchar();while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){ /*freopen("data1.in","r",stdin); freopen("date1.out","w",stdout);*/} vector<int> G[N]; int fa[N],vis[N]; int Find(int x) { return x == fa[x] ? x : fa[x] = Find(fa[x]); } int main() { int ca;ca = read(); while(ca--) { int n,m;n = read(),m = read(); for(rg int i = 1;i <= n;++i) G[i].clear(),fa[i] = i,vis[i] = 0; while(m--) { int u,v;u = read(),v = read(); G[u].push_back(v); G[v].push_back(u); int xx = Find(u),yy = Find(v); if(xx > yy) fa[xx] = yy; else fa[yy] = xx; } priority_queue<int,vector<int>,greater<int> > Q; int cnt = 0; for(rg int i = 1;i <= n;++i) if(fa[i] == i) Q.push(i),vis[i] = 1,cnt++; vector<int> ans; while(!Q.empty()) { int u = Q.top(); Q.pop(); ans.push_back(u); for(auto v : G[u]) { if(!vis[v]) vis[v] = 1,Q.push(v); } } printf("%d\n",cnt); for(int i = 0;i < ans.size();++i) printf("%d%c",ans[i],i == ans.size()-1 ? '\n' : ' '); } system("pause"); return 0; }
C:考慮m個點裡選擇n-1個不同的點,然後除了最大的值外,其他值都能出現兩次,那麼有出現兩次的點有(n-2)種。
那麼重複出現的點在左右兩邊交換的時候,還是不改變。對於出現一次的點(除了最大值),它在最大值左右兩邊都是不同的方案。
那麼ans = C(m,n-1) * (n-2) * 2^(n-3)
// Author: levil #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> using namespace std; typedef long long LL; typedef long double ld; typedef pair<int,int> pii; const int N = 2e5+5; const int M = 1e4; const LL Mod = 998244353; #define rg register #define pi acos(-1) #define INF 1e9 #define INM INT_MIN #define dbg(ax) cout << "now this num is " << ax << endl; namespace FASTIO{ /*const int BUF_SIZE = 8e7; inline char nc(){ static char buf[BUF_SIZE],*p1 = buf,*p2 = buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,BUF_SIZE,stdin),p1==p2)?EOF:*p1++; }*///file close. inline int read(){ int x = 0,f = 1;char c = getchar(); while(c < '0' || c > '9'){if(c == '-') f = -1;c = getchar();} while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();} return x*f; } void print(int x){ if(x < 0){x = -x;putchar('-');} if(x > 9) print(x/10); putchar(x%10+'0'); } } using namespace FASTIO; void FRE(){ /*freopen("data1.in","r",stdin); freopen("date1.out","w",stdout);*/} LL f[N]; void init() { f[0] = 1;for(rg int i = 1;i < N;++i) f[i] = f[i-1]*i%Mod; } LL quick_mi(LL a,LL b) { LL re = 1; while(b) { if(b&1) re = re*a%Mod; a = a*a%Mod; b >>= 1; } return re; } LL inv(LL n){return quick_mi(n,Mod-2);} LL C(LL n,LL m){return f[n]*inv(f[m])%Mod*inv(f[n-m])%Mod;} int main() { init(); int n,m;n = read(),m = read(); if(n <= 2) printf("0\n"); else{ LL ma = C(m,n-1);//m個數裡選n-1個不一樣的。 LL ans = ma*(n-2)%Mod*quick_mi(2,n-3)%Mod; printf("%lld\n",ans); } // system("pause"); return 0; }View Code