1. 程式人生 > 實用技巧 >《陝西師範大學第九屆ACM程式設計競賽》

《陝西師範大學第九屆ACM程式設計競賽》

A:其實並不是特別難的一個題,想的太複雜了。

首先,我們把關係看成能夠傳遞的,那麼我們並查集統計連通塊之後。

可以發現,對於一個連通塊,最優方案肯定只有1個人會沒朋友。

因為一直把和當前刪的點有關係的人的人刪進去,最後肯定就能刪完全部點,並且保證只有第一個進去的人沒朋友。

因為要保證字典序最小,我們每次合併並查集的時候,都讓大的以小的為父節點,那麼最後這個集合的根,肯定就是這個集合裡最小的點。

那麼我們先把根都扔到小頂堆裡,然後在把和堆頂相鄰的沒刪的元素放入,因為小頂堆,會自己保證最小字典序。

// 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 = 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; 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);*/} 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; }
View Code

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