题目大意:
有一个图,你要选定三个点,保证三个点之间两两无互相连边,当点 i<j<k i < j < k 的时候,你获得的收益为 A∗i+B∗j+C∗k A ∗ i + B ∗ j + C ∗ k ,求所有符合情况的收益和。
思路:
可以用容斥原理,即所有的情况 − − 至少有一对有连边至少有两对有连边 − − 三对都有连边 。
- 对于所有的情况,可以考虑每个点来算贡献
- 对于至少有一对连边的情况,可以枚举一个点和它的连边,然后用前缀和计算处余下来的所有的点。
- 对于至少有两对连边的情况,可以枚举中间那个于两个点都有连边的点,然后对于它连接的每一个点计算贡献
- 至于计算三元环,提供两种同样都是的方法:第一种即暴力枚举每一条边然后再枚举这条边的度数较少的那个端点的边,然后判断剩下两点之间有无连边。还有一种方法就是对于度数小于
m−−√
m
的点枚举两条边,对于度数大于
m−−√
m
的点直接
n3
n
3
枚举,由于后面的点之多只有
m−−√
m
个,所以总的复杂度为
O(mm−−√)
O
(
m
m
)
。
然后注意在计算的过程中別爆int了。/*========================== * Author : ylsoi * Problem : girls * Algorithm : counting * Time : 2018.6.26 * ========================*/ #include<bits/stdc++.h> #include<tr1/unordered_map> #define REP(i,a,b) for(int i=a;i<=b;++i) #define DREP(i,a,b) for(int i=a;i>=b;--i) typedef long long ll; using namespace std; void File(){ freopen("20180625T2.in","r",stdin); freopen("20180625T2.out","w",stdout); } const int maxn=2e5+10; int n,m; unsigned long long de[maxn],A,B,C,ans,suma[maxn],sumb[maxn],sumc[maxn]; vector<int>to[maxn]; tr1::unordered_map<int,bool>G[maxn]; void init(){ scanf("%d%d",&n,&m); cin>>A>>B>>C; REP(i,1,m){ int u,v; scanf("%d%d",&u,&v); ++u; ++v; ++de[u]; ++de[v]; to[u].push_back(v); to[v].push_back(u); G[u][v]=1; G[v][u]=1; } REP(i,1,n)sort(to[i].begin(),to[i].end()); } void cal(){ REP(i,1,n){ ans+=A*(i-1)*((ll)(n-i-1)*(n-i)/2); ans+=B*(i-1)*(i-1)*(n-i); ans+=C*(i-1)*((ll)(i-1)*(i-2)/2); } REP(i,1,n){ suma[i]=suma[i-1]+(i-1)*A; sumb[i]=sumb[i-1]+(i-1)*B; sumc[i]=sumc[i-1]+(i-1)*C; } REP(i,1,n){ int siz=to[i].size()-1; unsigned long long cnt0=0,cnt1=0; REP(j,0,siz){ int v=to[i][j]; v<i ? (++cnt0) : (++cnt1); if(v<i){ ans-=suma[v-1]+B*(v-1)*(v-1)+C*(i-1)*(v-1); ans+=A*(v-1)*(siz-j)+B*(v-1)*j; } else{ ans-=A*(i-1)*(n-v)+B*(v-1)*(n-v)+sumc[n]-sumc[v]; ans-=A*(i-1)*(v-i-1)+sumb[v-1]-sumb[i]+C*(v-1)*(v-i-1); ans+=C*(v-1)*j+B*(v-1)*(siz-j); } } ans+=A*(i-1)*(cnt1*(cnt1-1)/2)+B*(i-1)*cnt0*cnt1+C*(i-1)*cnt0*(cnt0-1)/2; } } bool cmp(int _,int __){return de[_]<de[__];} void find_circle(){ int qu[maxn]; REP(i,1,n)qu[i]=i; sort(qu+1,qu+n+1,cmp); int t=1,qq[3]; while(t+1<=n && de[qu[t+1]]<=sqrt(m))++t; unsigned long long s[4]={0}; REP(i,1,t){ int u=qu[i],siz=to[u].size()-1; REP(j,0,siz)REP(k,j+1,siz)if(G[to[u][j]][to[u][k]]){ int cnt=0; qq[0]=u; qq[1]=to[u][j]; qq[2]=to[u][k]; REP(l,0,2)if(de[qq[l]]<=sqrt(m))++cnt; sort(qq,qq+3); s[cnt]+=(qq[0]-1)*A+(qq[1]-1)*B+(qq[2]-1)*C; } } ans-=s[1]+s[2]/2+s[3]/3; REP(i,t+1,n)REP(j,i+1,n)REP(k,j+1,n) if(G[qu[i]][qu[j]] && G[qu[j]][qu[k]] && G[qu[i]][qu[k]]){ qq[0]=qu[i]; qq[1]=qu[j]; qq[2]=qu[k]; sort(qq,qq+3); s[0]+=(qq[0]-1)*A+(qq[1]-1)*B+(qq[2]-1)*C; } ans-=s[0]; } int main(){ File(); init(); cal(); find_circle(); cout<<ans<<endl; return 0; }