【LOJ】 #2547. 「JSOI2018」防御网络

题解

如果只是一棵树的话,那么就枚举每条边,分成两部分大小为\(a\)\(b\)
那么这条边被统计的方案数是\((2^a - 1)(2^b - 1)\)

如果是一个环的话,我们枚举环上至少有\(N - i\)条边的方案数\(T(N - i)\)
\(\sum_{i = 1}^{N - 1}T(N - i)\)
先枚举一个\(i\)
就是枚举\([1,n]\)中最靠左的\(l\)和最靠右的\(r\)的方案数\(g[l][r]\),且间隔不超过\(i\)
用前缀和优化更新

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define mp make_pair
#define pb push_back
#define enter putchar('\n')
#define space putchar(' ')
#define MAXN 205
#define eps 1e-8
//#define ivorysi
using namespace std;
typedef long long int64;
typedef double db;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
	if(c == '-') f = -1;
	c = getchar();
    }
    while(c >= '0' && c <= '9') {
	res = res * 10 + c - '0';
	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {x = -x;putchar('-');}
    if(x >= 10) {
	out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 1000000007;
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
int fpow(int x,int c) {
    int res = 1,t = x;
    while(c) {
        if(c & 1) res = mul(res,t);
        t = mul(t,t);
        c >>= 1;
    }
    return res;
}
void update(int &x,int y) {
    x = inc(x,y);
}
struct node {
    int to,next;
}E[MAXN * 10];
int head[MAXN],sumE,N,M;
int dfn[MAXN],low[MAXN],siz[MAXN],idx,sta[MAXN],top;
int A[MAXN],tot,pw2[MAXN],ans,g[MAXN],sum[MAXN];
void add(int u,int v) {
    E[++sumE].to = v;
    E[sumE].next = head[u];
    head[u] = sumE;
}
void Calc() {
    if(tot == 2) {update(ans,mul(pw2[A[1]] - 1,pw2[A[2]] - 1));return;}
    for(int k = 1 ; k < tot ; ++k) {
        for(int i = 1 ; i <= tot ; ++i) {
            memset(g,0,sizeof(g));
	    memset(sum,0,sizeof(sum));
	    g[i] = pw2[A[i]] - 1;sum[i] = g[i];
	    for(int j = i + 1 ; j <= tot ; ++j) {
		g[j] = mul(pw2[A[j]] - 1,inc(sum[j - 1],MOD - sum[max(j - k - 1,0)]));
		sum[j] = inc(sum[j - 1],g[j]);
		if(i + tot - j <= k) update(ans,g[j]);
	    }
        }
    }
}
void Tarjan(int u) {
    dfn[u] = low[u] = ++idx;
    sta[++top] = u;
    siz[u] = 1;
    for(int i = head[u] ; i ; i = E[i].next) {
        int v = E[i].to;
        if(dfn[v]) {low[u] = min(low[u],dfn[v]);}
        else {
            Tarjan(v);
            if(low[v] >= dfn[u]) {
                int s = 0;
                tot = 0;
                while(1) {
                    int x = sta[top--];
                    s += siz[x];
                    A[++tot] = siz[x];
                    if(x == v) break;
                }
                A[++tot] = N - s;
		siz[u] += s;
		Calc();
            }
            low[u] = min(low[v],low[u]);
        }
    }
}
void Solve() {
    read(N);read(M);
    int u,v;
    for(int i = 1 ; i <= M ; ++i) {
        read(u);read(v);
        add(u,v);add(v,u);
    }
    pw2[0] = 1;
    for(int i = 1 ; i <= N ; ++i) {
        pw2[i] = mul(pw2[i - 1],2);
    }
    Tarjan(1);
    ans = mul(ans,fpow((MOD + 1) / 2,N));
    out(ans);enter;
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Solve();
}
posted @ 2018-11-23 11:29  sigongzi  阅读(327)  评论(0编辑  收藏  举报