题目链接: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('\n') 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<<"\n"; 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 ull num=n-sz[x]-sz[y]; 69 ull temp=c2-sz[x]*num-sz[y]*num-sz[x]*sz[y];///减去不满足的情况 70 ans-=sz[x]*sz[y]*temp; 71 c2-=sz[x]*sz[y]; ///减去两个集合各取一个的情况 72 f[x]=y; 73 sz[y]+=sz[x]; 74 write(ans);pn; 75 } 76 return 0; 77 }