题目链接:杭电problems6795
题解太过于玄乎,我写一下直接用数学式子解决的方法把:
我们把1能力的选手和2能力的选手分成两堆:
能力1选手数量为:n
能力2选手数量为:m
每一次操作其实就是两个连通块给连起来对不对?我们初始化:每一个点都是一个连通块,能力为1的选手的连通块我们在根节点用a=1,b=0表示这个连通块的能力为1选手数量为1,能力为2选手数量为0;
那么我们0次操作后的答案是很容易求出来的:C(2,m)*n+C(3,m)。
我们用last变量存上一次操作的答案。
在某次操作,我们把a1,b1属性的连通块和a2,b2属性的连通块连在一起,那么就是说:
1 a1 , a2 , n - a1 - a2
2 b1 , b2 , m - b1 - b2
当把三块分出来,我们可以捋清楚了以下四个情况:
原本b1一个,b2一个,(n-a1-a2)一个可以,现在不行了
原本b1一个,b2一个,(m-b1-b2)一个可以,现在不行了
原本b1一个,a2一个,(m-b1-b2)一个可以,现在不行了
原本a1一个,b2一个,(m-b1-b2)一个可以,现在不行了
那么last=last-b1b2(n-a1-a2)-b1b2(m-b1-b2)-b1a2(m-b1-b2)-b2a1(m-b1-b2)
Code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//
using namespace std;
const int INF = 0x3f3f3f3f;//1.06e9大小
const int mod1 = 1e9 +7;
const int mod2 = 998244353;
const int mod3 = 1e9;
const double PI = acos(-1);
const double eps =1e-8;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned uint;
const int sq5=616991993;
#define ms(x, n) memset(x,n,sizeof(x))
#define debug printf("***debug***\n")
#define pii pair
#define X first
#define Y second
#define pb push_back
#define ls(i) i<<2
#define rs(i) i<<2|1
#define lowbit a&(-a)
/*
*/
int t,tot;
ll n,m,last;
const int maxn = 1e5+100;
struct Root
{
ll a,b;
}root[maxn];
int fa[maxn];
int getfather(int k){if(fa[k]==k)return k;return fa[k]=getfather(fa[k]);}
void out(ll a1 ,ll b1 ,ll a2 ,ll b2)
{
ll res=0;
res=(res+b1*b2*(n-a1-a2))%mod1;
res=(res+b1*b2*(m-b1-b2))%mod1;
res=(res+b1*a2*(m-b1-b2))%mod1;
res=(res+b2*a1*(m-b1-b2))%mod1;
last=(last-res+mod1)%mod1;
printf("%lld\n",last);
}
void mer(int from ,int to )
{//连接函数
int x=getfather(from);
int y=getfather(to);
fa[x]=y;
out(root[y].a ,root[y].b ,root[x].a ,root[x].b );
root[y].a+=root[x].a;
root[y].b+=root[x].b;
}
int main()
{
cin>>t;
while(t--)
{
n=0,m=0;//n个1,m个2
scanf("%d",&tot);
for(int i=1;i<=tot;++i)
{
int num=0;
scanf("%d",&num);
fa[i]=i;
if(num==1)
{
++n;
root[i]={1,0};
}
else
{
++m;
root[i]={0,1};
}
}
last=(m*(m-1)*(m-2)/6)%mod1+((m*(m-1)*n)/2)%mod1;
last %=mod1;
printf("%lld\n",last);
for(int i=1;i<tot;++i)
{//询问
int u,v;//u的root连到v的root上
scanf("%d %d",&u,&v);
mer(u,v);
}
}
return 0;
}