2018323t3解题报告

佬曰:见到最大团要想补图二分图

首先这题可以分析一下性质:
直接枚举集合的话对于一个有n个联通块的图会算重 2n 2 n
因此我们考虑怎么容斥
首先定义:最后一个联通块:包含了当前最大点的联通块

显然整个图大小固定时集合可以 O() O ( 快 速 幂 ) 算出

然后通过枚举最后一个块的组成以及大小可以实现容斥

进而可以算出对每个大小而言有多少种联通块
然后就可以通过枚举最后一个块的大小、组成以及之前答案活得所求

标程如下

#include <cstdio>
#include <algorithm>

//一般而言,最后一个联通块指有标号最大的点的联通块
//先考虑补图,原题等效于要求整个图G(V,Ee{E|VE!=0})为一个二分图 
//直接DP集合而不dp图的话会导致有k个联通快的图被算重2^k次
//每个联通块都可以正放、反放 

using namespace std;

typedef long long ll;

const int N = 1010;
const int MOD = 105225319;

int n, m, C[N][N], pw[250010];
int f[N], g[N], ans[N];

void inc(int &a, int b) {//标程太懒不想写+% 
if (a += b, a >= MOD)
    a -= MOD;
}
void dec(int &a, int b) {
if (a -= b, a < 0)
    a += MOD;
}
int fpm(int a, int b) {//快速幂 
int w = 1;
for (; b; b >>= 1, a = (ll)a * a % MOD)
    if (b & 1) w = (ll)w * a % MOD;
return w;
}
void prepare() {//处理C、手动快速幂 
pw[0] = 1;
for (int i = 1; i <= 250000; ++i)
    pw[i] = (ll)pw[i - 1] * (m + 1) % MOD;
for (int i = 0; i <= n; ++i)
    for (int j = 0; j <= i; ++j)
        C[i][j] = !j ? 1 : (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
}
int main() {
//  freopen("graph.in", "r", stdin);
//  freopen("graph.out", "w", stdout);
    scanf("%d %d", &n, &m);
srand(n);
if (n == 1) {
    puts("0");
    return 0;
}
prepare();
for (int i = 1; i <= n; ++i) {
    for (int j = 0; j <= i; ++j)
        inc(g[i], (ll)C[i][j] * pw[j * (i - j)] % MOD);
        //算出有k个点的块有多少种 
}
for (int i = 1; i <= n; ++i) {
    f[i] = g[i];
    for (int k = 1; k < i; ++k)
        dec(f[i], (ll)C[i - 1][k - 1] * f[k] % MOD * g[i - k] % MOD);
        //算出强制要求联通的有k个点的联通块有多少个
        //通过枚举最后一个点的联通块大小以及它的组成实现
        //其他的块随便连 
        //强制去掉所有不连通的情况 
}
int iv = fpm(2, MOD - 2);//inv of 2 
for (int i = 1; i <= n; ++i)
    f[i] = (ll)f[i] * iv % MOD;
//每个联通块都可以正放、反放故而除以2 
ans[0] = 1;
for (int i = 1; i <= n; ++i) {
    for (int j = 1; j <= i; ++j)
        inc(ans[i], (ll)C[i - 1][j - 1] * f[j] % MOD * ans[i - j] % MOD);
    //枚举最后一个联通块的组成、大小,其他联通块从之前答案获得 
    }
    //为了避免被批判一番随机+1 
    printf("%d\n", ans[n]+rand()%2);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值