2019牛客暑期多校训练营(第九场)E All men are brothers(并查集+组合数学)

题目链接:https://ac.nowcoder.com/acm/contest/889/E

题目大意:从n个人中选出4个不能互相是朋友的方案数,每轮会有一对成为朋友,回答m个询问。

解题报告:设合并集合x和集合y,对于剩下的部分z为n-sz[x]-sz[y],对于前一次的方案,我们要减掉

  1.x集合中选1个人,y集合中选2个人,z中1个人

  2.x集合中选2个人,y集合中选1个人,z中1个人

  3.x集合中选2个人,y集合中选2个人,z中0个人

  这三种情况。

  所以可以通过维护一个选2人的组合数来解决。

  codeblock没法编译int128类型的,所以求组合数就只好通过打表解决了。

AC代码:

 1 #include<bits/stdc++.h>
 2 #define numm ch-48
 3 #define pd putchar(' ')
 4 #define pn putchar('
')
 5 #define pb push_back
 6 #define fi first
 7 #define se second
 8 #define fre1 freopen("1.txt","r",stdin)
 9 #define fre2 freopen("2.txt","w",stdout)
10 #define debug(args...) cout<<#args<<"->"<<args<<"
";
11 using namespace std;
12 template <typename T>
13 void read(T &res) {
14     bool flag=false;char ch;
15     while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true);
16     for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm);
17     flag&&(res=-res);
18 }
19 template <typename T>
20 void write(T x) {
21     if(x<0) putchar('-'),x=-x;
22     if(x>9) write(x/10);
23     putchar(x%10+'0');
24 }
25 typedef long long ll;
26 typedef unsigned long long ull;
27 const int maxn=100010;
28 const int maxm=505;
29 const int mod=1e9+7;
30 const int inv2=500000004;
31 int f[maxn],sz[maxn];
32 ll c[maxn][5];
33 int getf(int v) {
34     return f[v]==v?v:(f[v]=getf(f[v]));
35 }
36 void init() {
37     c[0][0]=1;
38     for(int i=1;i<=maxn-10;i++) {
39         c[i][0]=1;
40         for(int j=1;j<=min(i,4);j++)
41             c[i][j]=c[i-1][j]+c[i-1][j-1];
42     }
43 }
44 int main()
45 {
46 //    #define local
47     #ifdef local
48         fre1;
49 //        fre2;
50     #endif // local
51     int n,m;
52     init();
53     read(n),read(m);
54     for(int i=1;i<=n;i++)
55         sz[i]=1,f[i]=i;
56     ll c2=c[n][2];    ///维护一个取两个数的组合数
57     ll ans=c[n][4];
58     write(ans);pn;
59     while(m--) {
60         int a,b;
61         read(a),read(b);
62         int x=getf(a);
63         int y=getf(b);
64         if(x==y) {
65             write(ans);pn;
66             continue;
67         }
68         ll num=n-sz[x]-sz[y];
69         ll temp=c2-sz[x]*num-sz[y]*num-sz[x]*sz[y];///减去不满足的情况
70         ans-=sz[x]*sz[y]*temp;  ///temp为z中取2个人的合法情况,现在x和y为一伙人,要减掉这种情况
71         c2-=sz[x]*sz[y];        ///减去两个集合各取一个的情况
72         f[x]=y;
73         sz[y]+=sz[x];
74         write(ans);pn;
75     }
76     return 0;
77 }
代码在这里!
原文地址:https://www.cnblogs.com/wuliking/p/11363519.html