链接:Problem - 7293 (hdu.edu.cn)
思路:
枚举度大于4 和 6 且 共同连接 4个以上点 的两个点, 其度分别记为a 和 b
若a为上面的点, 那么答案为C(a-4, 2) * C(b, 4), 反之同理
如果直接搜点会tle, 此时用bitset优化, 状态压缩, 时间复杂度为O(n^3 /32)
代码如下:
#include<iostream>
#include<bitset>
using namespace std;
typedef long long ll;
const int N = 1010, mod = 1e9+7;
int fact[N], infact[N];
bitset<N> g[N];
int qmi(int a, int k, int p)
{
int res = 1 % p;
while(k)
{
if (k & 1) res = (ll)res * a % p;
a = (ll)a * a % p;
k >>= 1;
}
return res;
}
void init()
{
fact[0] = infact[0] = 1;
for(int i = 1; i < N; i++)
{
fact[i] = (ll)fact[i-1] * i % mod;
infact[i] = (ll)infact[i-1] * qmi(i, mod-2, mod) % mod;
}
}
int C(int a, int b)
{
if(b > a) return 0;
return (ll)fact[a] * infact[b] % mod * infact[a - b] % mod;
}
void solve()
{
int n, m;
cin >> n >> m;
for(int i = 1; i <= n; i++) g[i].reset();
for(int i = 1; i <= m; i++)
{
int a, b;
cin >> a >> b;
g[a].set(b), g[b].set(a);
}
int res = 0;
for(int i = 1; i <= n; i++)
{
for(int j = i + 1 ; j <= n; j++)
{
auto tmp = g[i] & g[j]; //bitset<N>
int cnt = tmp.count();
if (tmp.count() >= 4)
{
int a = g[i].count(), b = g[j].count();
if(g[i][j]) a--, b--;//如果点i到j有边的话, 就减去这条边
if(a >= 6)
res = (res + (ll)C(cnt, 4) * C(a-4, 2)) % mod;
if(b >= 6)
res = (res + (ll)C(cnt, 4) * C(b-4, 2)) % mod;
}
}
}
cout << res << endl;
}
int main()
{
cin.tie(0); cout.tie(0); ios::sync_with_stdio(0);
int T;
cin >> T;
init();
while(T--) solve();
return 0;
}