codechef Sum of Cubes 图论

扶醉桌前 提交于 2019-12-31 03:43:03

正解:图论+数学

解题报告:

先放个传送门QwQ

然后放下题目大意?就说给定简单图,无自环或重边,然后求(∑e[i][j])k,i,j∈S,S为点集的子集

然后因为k的取值只有[1,3],所以这里分类讨论说下这题QAQ

首先k=1

k=1就比较简单昂,可以直接考虑每条边的贡献,所以就直接考虑如果这个边有贡献,一定是它的两个端点被选了,然后其他点随便选,所以答案就m*2n-2,做完辣

然后k=2

考虑组合意义?所以平方就相当于是说,有顺序地选两条边,求这个图包含了这两条边的方案数

那就和k=1一样的考虑,分情况讨论一下就好嘛

如果两条边是同一条边,就2n-2

如果它们有一个共同的端点,就2n-3

如果他们麻油共同的端点,就2n-4

然后就做完辣

还是说下统计边趴QAQ

首先是同一条边显然是有m种

然后有一个共同的端点可以通过枚端点,每个端点会有du[i]*(du[i]-1)的贡献

然后麻油共同的端点就是总数-同一条边的方案-有共同顶点的方案

over

最后就k=3

和k=2差不多,只是说要求的是,选三条边

然后就熟悉的分类讨论

因为考虑到不同的方案的差别主要在于是×2的几次方,也就是说只和这些边的端点个数有关,所以依然按端点数分类讨论

首先两个端点,就同一条边,一样的

三个端点,就有两条边是一条边还有一条边是和他们同端点的,或者是个三元环

四个端点,就有两条边是一条边而且第三条边不共端点或一条链或菊花图

五个端点,就两条链

六个端点,就三条边分别无交

然后三条边都同一条的情况,两条边是同一条的情况,就都比较简单,和上面那个k=2的也差不蛮多,skip

下面剩下来的就分别有

三元环

一条链

菊花图

一条链一条边

三条边分别无交

这里要安利一下,mlogm求三元环的做法,但是为了逻辑的连贯性,把这个做法的科普放到最后边QAQ

然后先分别说下其他几个的求法

首先对于一条链的,就枚举中间那条边是什么,然后另外两条边的方案数就是(du[i]-1)*(du[j]-1),但是这样可能会枚到三元环,所以要减去三元环的数量,又因为有三条边可能枚三次,所以最后的答案要减去三元环的个数*3

然后对于菊花图,就枚举那个中心的点,所以方案就是du[i]*(du[i]-1)*(du[i]-2)

然后对于两条链的,想到它肯定是一个两条边一个一条边,所以先枚举两条边的那个共同的端点,再随便枚举一条边就欧克了,但这里注意到,又是可能会枚到三元环的,然后还可能枚举到一条链,其中三元环依然是每条边被枚一次,一条链会被枚两次(就两边的边可能会被枚到嘛),所以最后的答案-三元环的个数*3-一条链的个数*2

三条边分别无交依然是总量-其他方案数就over辣

最后要解决的就,三元环的个数

这里用到的方法就,对每条边重新正式连单向边,从度数小的指向度数大的,如果度数相等就从编号小的指向编号大的

然后这里为了区分两种边,原来的边叫双向边,后来的叫单向边

就枚举双向边,然后选这个双向边的一端(具体哪一段其实是有要求的,指的是度数小的那一端,为什么我不知道但代码是这样儿的QAQ),把这一端的单向边连向的所有点染色,然后再看这个双向边的另一端的单向边指向的点,如果是这个颜色,说明是个三元环,ans++

更简单粗暴的方法可以直接开个vector,然后枚两个端点的vector,如果有相等的元素就++as,反正思想都一样儿的就是辣,只是实现上有一定的区别而已QAQ

好滴写完了

然后关于具体代码注意两个地方,一个是k=2的时候我是直接做的,但其实本来应该是要去重的就要/2的,但因为是说有顺序的,所以就又*2就抵消掉了,代码中就麻油体现出来这一步了,另一个其实是一样的,就k=3的时候要*6,我在后面一起*6了,这个点不算是要注意只是解释下为什么要*6

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define int long long
#define gc getchar()
#define ri register int
#define rc register char
#define rb register bool
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)

const int N=1e5+100,mod=1e9+7;
int n,m,K,fr[N],to[N],poww[N]={1},du[N],vis[N];
vector<int>nod[N];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch<'0' || ch>'9'))ch=gc;
    if(ch=='-')y=0,ch=gc;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
namespace gd
{
    int solve()
    {
        ri as1=m*m%mod,as2=0,as3=m;
        rp(i,1,n)as2=(as2+du[i]*(du[i]-1))%mod;
        as1=(as1-as2+mod)%mod;as1=(as1-as3+mod)%mod;
        if(n>=3)as3=(as3*poww[n-2]+as2*poww[n-3])%mod;
        if(n>=4)as3=(as3+as1*poww[n-4])%mod;
        return as3;
    }
}
namespace gs
{
    int solve()
    {
        ri as3=0,as4=0,asas4=0,as5=0,as6=0,as=0;
        rp(i,1,n)nod[i].clear();
        rp(i,1,m)
        {
            if(du[fr[i]]>du[to[i]] || (du[fr[i]]==du[to[i]] && fr[i]>to[i]))swap(fr[i],to[i]);
            nod[fr[i]].push_back(to[i]);
        }
        rp(i,1,n)
        {
            for(ri j:nod[i])vis[j]=i;
            for(ri j:nod[i])for(ri k:nod[j])if(vis[k]==i)as3=(as3+1)%mod;
        }
        rp(i,1,m)as4=(as4+(du[fr[i]]-1)*(du[to[i]]-1)%mod)%mod;as4=(as4-3*as3+mod*3)%mod;
        rp(i,1,n)asas4=(asas4+du[i]*(du[i]-1)*(du[i]-2)/6%mod)%mod;
        rp(i,1,n)as5=(as5+du[i]*(du[i]-1)/2%mod*(m-2)%mod);
        as5=(as5-2*as4%mod+mod)%mod;as5=(as5-3*as3%mod+mod)%mod;as5=(as5-3*asas4%mod+mod)%mod;
        as6=m*(m-1)*(m-2)/6%mod;as6=(as6-as5+mod-as4+mod-asas4+mod-as3+mod)%mod;
        if(n>=6)as=(as+as6*poww[n-6]%mod)%mod;
        if(n>=5)as=(as+as5*poww[n-5]%mod)%mod;
        if(n>=4)as=(as+as4*poww[n-4]%mod+asas4*poww[n-4]%mod)%mod;
        if(n>=3)as=(as+as3*poww[n-3]%mod)%mod;
        as=as*6%mod;as=(as-2*m*poww[n-2]%mod+mod)%mod;as=(as+gd::solve()*3%mod)%mod;
        return as;
    }
}


main()
{
    freopen("t2.in","r",stdin);freopen("t2.out","w",stdout);
    int T=read();rp(i,1,N-10)poww[i]=(poww[i-1]<<1)%mod;
    while(T--)
    {
        memset(du,0,sizeof(du));memset(vis,0,sizeof(vis));
        n=read();m=read();K=read();
        rp(i,1,m)++du[fr[i]=read()],++du[to[i]=read()];
        if(K==1)printf("%lld\n",m*poww[n-2]%mod);
        if(K==2)printf("%lld\n",gd::solve());
        if(K==3)printf("%lld\n",gs::solve());
    }
    return 0;
}
这儿是代码QAQ

 

overr,我晚上补QAQ

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!