zoukankan      html  css  js  c++  java
  • luogu3244 bzoj4011 HNOI2015 落忆枫音

    这道题目题面真长,废话一堆。

    另外:这大概是我第一道独立做出来的HNOI2011年以后的题目了吧。像我水平这么差的都能做出来,dalao您不妨试一下自己想想?

    题目大意:给一个DAG,其中1号点没有入度,现在新加入一条不重复的边,使得它可能有环。求它的生成子图个数,使得子图正好包含N-1条边且1号点与其它的所有点连通。

    题目分析:

    我们首先要发现这是一个树的结构!有向的树。

    分析树的特点,树的父亲只有一个,我们不妨从这里入手。

    在这一个生成子图中,谁是谁的父亲?

    我们知道1号点一定是root,这是为什么呢?

    原因在于一号点没有入度,我们就认为了它是root。

    那么假设有一条x->y的路径,那么x就是y的父亲,这样的定义是合理的。

    考虑不加边之前的情况,图是一个DAG,我们求它的生成树(姑且这么叫吧)。

    根据我们上面的分析,我们猜想:除一号点外所有点的入度乘积为该图的生成树数量。

    证明如下:

    首先我们考虑这个是怎么来的。每个点选择一个父亲,则根据乘法原理得到上面的猜想。

    那么我们的命题是:每个点选一个父亲,则这个方案必定合法。

    我们一共对N-1个点选了到fa的边,每次选择都合并了两个点,共合并了N-1次,因此共N个点被合并,又由于不存在环的情况,所以这样的方案是合法的。

    考虑多了一条边的情况。那么我们由于已经求得了所有不包含这条边的情况,我们只需要分析多了这条边的情况。

    假设这是一条从x到y的边。当这条边必选的时候,y点必定不被考虑。因为它的父亲已经确定。

    那么我们对剩下的点重新做一遍乘法,得到了ans2。

    考虑答案多了什么。

    当选出的边与当前边成环的时候,这个并不是一个生成树,我们没办法解决了吗?当然不是。

    我们不妨单独拿出一个环考虑。当形成了这个环的时候,对答案的影响是多少。实际上这不难统计,把剩下的点的入度全部乘起来就是答案。嘿嘿,这不就是总和除以现在的点数吗。

    那么我们考虑求y到x的路径的点的入度的逆,DP一发轻松解决。然后乘法分配率证明正确性。

    后记:这题我先写了个错的然后发现我想错了,答案小了,调了调变大了,然后又调,结果搜索出了正解233。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long ll;
    
    const int maxn = 102000;
    const int mod = 1000000007;
    int n,m,x,y;
    ll ans,ans2;
    int in[maxn],arr[maxn];
    ll dist[maxn],inv[maxn];
    vector <int> g[maxn];
    vector <int> ng[maxn];
    
    ll fast_pow(int now,int p){
        if(p == 1) return now;
        if(p == 0) return 1;
        ll z = fast_pow(now,p/2); z*=z; z %= mod;
        if(p & 1){z*=now;z%=mod;}
        return z;
    }
    
    void read(){
        scanf("%d%d%d%d",&n,&m,&x,&y);
        for(int i=1;i<=m;i++){
            int a,b; scanf("%d%d",&a,&b);
            g[a].push_back(b);in[b]++;
            ng[b].push_back(a);
        }
        for(int i=2;i<=n;i++) inv[i] = fast_pow(in[i],mod-2);
    }
    
    void dfs(int now){
        if(arr[now]) return;
        arr[now] = 1;
        for(int i=0;i<ng[now].size();i++){
            dfs(ng[now][i]);
            dist[now] += (dist[ng[now][i]]*inv[now])%mod;
            dist[now] %= mod;
        }
    }
    
    void work(){
        ans = ans2 = 1;
        for(int i=2;i<=n;i++) ans = (ans*in[i]) % mod;
        if(x == y){printf("%lld
    ",ans);return;}
        if(y == 1){printf("%lld
    ",ans);return;}
        for(int i=2;i<=n;i++) if(i != y) ans2 = (ans2*in[i]) % mod;
        in[y]++;inv[y] = fast_pow(in[y],mod-2);dist[y] = inv[y];arr[y] = 1;dfs(x);
        ans += ans2; ans %= mod;
        ans -= (ans*dist[x])%mod; ans += mod; ans %= mod;
        printf("%lld
    ",ans);
    }
    
    int main(){
        read();
        work();
        return 0;
    }
  • 相关阅读:
    linux 短信收发
    sama5d3 环境检测 adc测试
    【Codeforces 723C】Polycarp at the Radio 贪心
    【Codeforces 723B】Text Document Analysis 模拟
    【USACO 2.2】Preface Numbering (找规律)
    【Codeforces 722C】Destroying Array (数据结构、set)
    【USACO 2.1】Hamming Codes
    【USACO 2.1】Healthy Holsteins
    【USACO 2.1】Sorting A Three-Valued Sequence
    【USACO 2.1】Ordered Fractions
  • 原文地址:https://www.cnblogs.com/1-1-1-1/p/8596753.html
Copyright © 2011-2022 走看看