2023“钉耙编程”中国大学生算法设计超级联赛(2)foreverlasting and fried-chicken
题目大意
首先引入题目中炸鸡的故事。
https://www.zhihu.com/question/62332494/answer/3076483871
给你一个有 n n n个点 m m m条边的无向图,求这个无向图中出现了多少个 foreverlasting \text{foreverlasting} foreverlasting图。
下面的图像定义了一个 foreverlasting \text{foreverlasting} foreverlasting图。
当两个
foreverlasting
\text{foreverlasting}
foreverlasting图的边集之间至少有一条不同的边时,这两个图被认为是不同的。
换句话说,设给定的图为 G ( V , E ) G(V,E) G(V,E),你需要计算满足 V ′ = { v 1 , v 2 , v 3 , v 4 , v 5 , v 6 , v 7 , v 8 } , E ′ = { ( v 1 , v 3 ) , ( v 2 , v 3 ) , ( v 3 , v 4 ) , ( v 3 , v 5 ) , ( v 3 , v 6 ) , ( v 3 , v 7 ) , ( v 4 , v 8 ) , ( v 5 , v 8 ) , ( v 6 , v 8 ) , ( v 7 , v 8 ) } V'=\{v_1,v_2,v_3,v_4,v_5,v_6,v_7,v_8\},E'=\{(v_1,v_3),(v_2,v_3),(v_3,v_4),(v_3,v_5),(v_3,v_6),(v_3,v_7),(v_4,v_8),(v_5,v_8),(v_6,v_8),(v_7,v_8)\} V′={v1,v2,v3,v4,v5,v6,v7,v8},E′={(v1,v3),(v2,v3),(v3,v4),(v3,v5),(v3,v6),(v3,v7),(v4,v8),(v5,v8),(v6,v8),(v7,v8)}的子图 G ′ ( V ′ , E ′ ) G'(V',E') G′(V′,E′)的数量。
输出答案模 1 0 9 + 7 10^9+7 109+7后的值。
有 t t t组数据。
1 ≤ t ≤ 10 , 1 ≤ n ≤ 1000 , 0 ≤ m ≤ n ( n − 1 ) 2 1\leq t\leq 10,1\leq n\leq 1000,0\leq m\leq \frac{n(n-1)}{2} 1≤t≤10,1≤n≤1000,0≤m≤2n(n−1)
数据保证 ∑ n ≤ 3000 \sum n\leq 3000 ∑n≤3000
题解
我们可以枚举 foreverlasting \text{foreverlasting} foreverlasting图中 v 3 v_3 v3和 v 8 v_8 v8的位置,这两个点分别称为 u u u和 v v v,设 v t vt vt为同时与 u , v u,v u,v连边的点的个数, c t u ct_u ctu为与 u u u连边的点的个数,那么对于这对 u , v u,v u,v, foreverlasting \text{foreverlasting} foreverlasting图的个数为
a n s u , v = C v t 4 × C c t u − 4 2 ans_{u,v}=C_{vt}^4\times C_{ct_u-4}^2 ansu,v=Cvt4×Cctu−42
所以答案为
a n s = ∑ u = 1 n ∑ v = 1 n a n s u , v × [ u ≠ v ] ans=\sum\limits_{u=1}^n\sum\limits_{v=1}^nans_{u,v}\times [u\neq v] ans=u=1∑nv=1∑nansu,v×[u=v]
注意要特判 u u u和 v v v连边的情况,如果连边,则将 c t u ct_u ctu减一,计算完 a n s u , v ans_{u,v} ansu,v之后再加回来。
时间复杂度为 O ( n 3 ) O(n^3) O(n3),加上 bitset \text{bitset} bitset优化后,时间复杂度为 O ( n 3 ω ) O(\dfrac{n^3}{\omega}) O(ωn3),可以通过本题。
code
#include<bits/stdc++.h>
using namespace std;
const long long mod=1000000007;
int tq,n,m,ct[1005];
long long vt,now,ans,ny2,ny24;
bitset<1005>wt,z[1005];
long long mi(long long t,long long v){
if(!v) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
int rd(){
int re=0;
char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9'){
re=re*10+ch-'0';
ch=getchar();
}
return re;
}
int main()
{
tq=rd();
ny2=mi(2,mod-2);
ny24=mi(24,mod-2);
while(tq--){
n=rd();m=rd();
for(int i=1,x,y;i<=m;i++){
x=rd();y=rd();
z[x][y]=z[y][x]=1;
++ct[x];++ct[y];
}
ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j) continue;
wt=z[i]&z[j];
vt=wt.count();
ct[i]-=z[i][j];
if(vt>=4&&ct[i]>=6){
now=vt*(vt-1)%mod*(vt-2)%mod*(vt-3)%mod*ny24%mod;
now=now*(ct[i]-4)%mod*(ct[i]-5)%mod*ny2%mod;
ans=(ans+now)%mod;
}
ct[i]+=z[i][j];
}
}
printf("%lld\n",ans);
for(int i=1;i<=n;i++){
ct[i]=0;
z[i].reset();
}
}
return 0;
}