2019牛客多校九E.All men are brothers(统计n个数中四个不同数的相乘和)

题目链接、

 

直接求四个不同的相乘不好求,那么维护三个的两个的和一个的,通过这三个来维护每次合并两个(删掉两个加上一个)造成的影响

注意一开始的C_{n}^{4}直接算的话爆掉longlong了,所以处理了一下

影响:

一二三四个,记为cot1+cot2+cot3+cot4,其中cot4即答案

为了方便,我自己创造了俩符号,用来方便思考和叙述,

A_{i}表示不去重的cot_{i},即选出n个中选出i个相乘(有顺序的)

A_{i}^{j}表示在cot_{i}中去掉a[j]造成的影响

D_{i}^{k}表示在cot_{i}中加上a[k]造成的影响(a[k]原先并不存在)

A_{1}=\sum_{i}^{n}a[i]=nA_{1}^{i}=A_{1}-a[i]D_{1}^{k}=A_{1}+a[k]

自己和自己并不需要相乘,那么统计和即可,去掉一个数,显然直接减掉,加上亦然

A_{2}=\sum_{i=1}^{n}a[i]*A_{1}^{i}A_{2}^{i}=A_{2}-a[i]*A_{1}^{i}D_{2}^{k}=A_{2}+a[k]*A_{1}

显然可以通过A_{1}来降低A_{2}的复杂度

A_{3}=\sum_{i=1}^{n}a[i]*A_{2}^{i}A_{3}^{i}=A_{3}-a[i]*A_{2}^{i}D_{3}^{k}=A_{3}+a[k]*A_{2}

一样,抄过来,改

A_{4}=\sum_{i=1}^{n}a[i]*A_{3}^{i}A_{4}^{i}=A_{4}-a[i]*A_{3}^{i}D_{4}^{k}=A_{4}+a[k]*A_{3}

一样,抄过来,改

注意到,去重后的A_{i},即cot_{i},也就是无顺序的A_{i},也就是除掉一个i!就好了。(就和排列组合类似的)

并不影响加一个和减一个数的具体操作,所以,我们一开始处理好cot,然后还是按照这个加加减减的方式进行处理就行了

 

尽管上面啰啰嗦嗦写了一堆乱七八糟的鬼话,但是结论挺简单的

 

减掉k

cot1 -= k;
cot2 -= k*cot1;
cot3 -= k*cot2;
cot4 -= k*cot3;

加上k

cot4 += k*cot3;
cot3 += k*cot2;
cot2 += k*cot1;
cot1 += k;

这个可以往上接着写cot5,cot6之类的

 

 

/*author:revolIA*/
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+7;
typedef long long ll;
int Fa[maxn];
ll Size[maxn];
ll cot1,cot2,cot3,cot4;
int Find(int x){
    return Fa[x]==x?x:Fa[x]=Find(Fa[x]);
}
void add(ll k){
    cot4 += k*cot3;
    cot3 += k*cot2;
    cot2 += k*cot1;
    cot1 += k;
}
void del(ll k){
    cot1 -= k;
    cot2 -= k*cot1;
    cot3 -= k*cot2;
    cot4 -= k*cot3;
}
int main(){
    ll n,m;
    scanf("%lld%lld",&n,&m);
    cot1 = cot2 = cot3 = cot4 = 0;
    for(int i=1;i<=n;i++)Size[i] = 1,Fa[i] = i,add(1LL);
    printf("%lld\n",cot4);
    while(m--){
        int x,y;
        scanf("%d%d",&x,&y);
        x = Find(x),y = Find(y);
        if(x == y){
            printf("%lld\n",cot4);
        }else{
            ll k1 = Size[x] , k2 = Size[y];
            del(k1),del(k2),add(k1+k2);
            Fa[x] = y;
            Size[y] += Size[x];
            printf("%lld\n",cot4);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值