bzoj5407: girls

题目描述:

大皮出行,妹子成群,似乎这种事早已经司空见惯了。 大皮最终还是厌倦了这样的⽣活,懂得了节制,他希望每次恰好只有三个妹子陪他。

 大皮有 $n$个妹子,编号为$0$到$n-1$ ,大皮需要次从$n$个中选出三个来愉悦身心。

那么问题来了,有许多妹子为了得到大皮的欢心,产生了冲突,这样的冲突一共有$m$组,为了让自己的出行能清净些,大皮不希望选出的三个妹子,有任何一对存在冲突。

对于每一次选择的三个妹子$i,j,k(i<j<k)$,大皮可以得到的愉悦值为

$A imes i+B imes j+C imes k$

大皮希望你帮他求出所有方案可以得到的愉悦值之和,由于答案太大,请输出答案$mod 2^{64}$

算法标签:三元环计数,容斥

思路:

对于满足的方案容斥一下。

所有方案-有一条边的+有两条边的-有三条边的

以下代码:

#include<bits/stdc++.h>
#define il inline
#define ull unsigned long long
#define _(d) while(d(isdigit(ch=getchar())))
using namespace std;
const int N=2e5+5;
bool vis[N];
ull A,B,C,ans;
int n,m,q[4],in[N];
struct node{
    int l,r;
}t[N];
vector<int> v[N];
il int read(){
    int x,f=1;char ch;
    _(!)ch=='-'?f=-1:f;x=ch^48;
    _()x=(x<<1)+(x<<3)+(ch^48);
    return f*x;
}
int main()
{
    n=read();m=read();
    scanf("%llu%llu%llu",&A,&B,&C);
    for(int i=1;i<=n;i++){
        if(i<n-1)ans+=A*(ull)(1ll*(n-i)*(n-i-1)/2)*(i-1);
        if(i!=1&&i!=n)ans+=B*(ull)(1ll*(i-1)*(n-i))*(i-1);
        if(i>2)ans+=C*(ull)(1ll*(i-1)*(i-2)/2)*(i-1);
    }
    for(int i=1;i<=m;i++){
        int x=read()+1,y=read()+1;
        in[x]++;in[y]++;
        t[i]=(node){x,y};
        if(x>y)swap(x,y);
        ans-=(ull)(B*(x-1)+C*(y-1))*(ull)(x-1)+A*(ull)(1ll*(x-1)*(x-2)/2ll);
        ans-=(ull)(A*(x-1)+C*(y-1))*(ull)(y-x-1)+B*(ull)(1ll*(y-x-1)*(x+y-2)/2ll);
        ans-=(ull)(A*(x-1)+B*(y-1))*(ull)(n-y)+C*(ull)(1ll*(n-y)*(y-1+n)/2ll);
        v[x].push_back(y);v[y].push_back(x);
    }
    for(int i=1;i<=n;i++)sort(v[i].begin(),v[i].end());
    for(int x=1;x<=n;x++){
        int sz=v[x].size()-1;
        int num1=0,num2=0;
        for(int i=0;i<=sz;i++){
            int to=v[x][i];
            if(to<x){
                num1++;
                ans+=A*(to-1)*(sz-i)+B*(to-1)*i;
            }
            else{
                num2++;
                ans+=B*(to-1)*(sz-i)+C*(to-1)*i;
            }
        }
        ans+=(ull)(x-1)*(A*(1ll*num2*(num2-1)/2)+B*(1ll*num1*num2)+C*(1ll*num1*(num1-1)/2));
    }
    for(int i=1;i<=n;i++)v[i].clear();
    for(int i=1;i<=m;i++){
        int x=t[i].l,y=t[i].r;
        if(in[x]<in[y]||(in[x]==in[y]&&x>y))swap(x,y);
        v[x].push_back(y);
    }
    for(int x=1;x<=n;x++){
        for(int i=0;i<v[x].size();i++)vis[v[x][i]]=1;
        for(int i=0;i<v[x].size();i++){
            int to=v[x][i];
            for(int j=0;j<v[to].size();j++){
                if(vis[v[to][j]]){
                    q[1]=x-1;q[2]=to-1;q[3]=v[to][j]-1;
                    sort(q+1,q+4);
                    ans-=A*q[1]+B*q[2]+C*q[3];
                }
            }
        }
        for(int i=0;i<v[x].size();i++)vis[v[x][i]]=0;
    }
    printf("%llu
",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Jessie-/p/10427874.html