• 【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('
    ')
    #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();
    }
    
  • 相关阅读:
    安卓目录分析——MainActivity.java和activity_main.xml
    安卓目录理解 —— AndroidMainifest.xml
    安卓教程列表
    安卓目录介绍
    ideal 安卓环境搭建
    ideal 2019激活 方法
    binding.gyp not found 安装java npm 报错
    vue-cli脚手架打包页面空白
    .java文件转为.class文件转jar包
    前端框架Vue自学之Vue基础语法(二)
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10006493.html
Copyright © 2020-2023  润新知