1. 程式人生 > >[bzoj4011][DP]落憶楓音

[bzoj4011][DP]落憶楓音

Description

「恆逸,你相信靈魂的存在嗎?」

郭恆逸和姚楓茜漫步在楓音鄉的街道上。望著漫天飛舞的紅楓,楓茜突然問出 這樣一個問題。
「相信吧。不然我們是什麼,一團肉嗎?要不是有靈魂……我們也不可能再見 到你姐姐吧。」 恆逸給出了一個略微無厘頭的回答。楓茜聽後笑了笑。
「那你仔細觀察過楓葉嗎?」 說罷,楓茜伸手,接住了一片飄落的楓葉。
「其實每一片楓葉都是有靈魂的。你看,楓葉上不是有這麼多脈絡嗎?我聽說,
楓葉上有一些特殊的位置,就和人的穴位一樣。脈絡都是連線在這些穴位之間的。
楓樹的靈魂流過每片楓葉的根部,沿著這些脈絡,慢慢漫進穴位,沁入整片楓葉。 也是因為這個原因,脈絡才都是單向的,靈魂可不能倒著溜回來呢。」
恆逸似懂非懂地點了點頭。楓茜接著說了下去。 「正是因為有了靈魂,每片楓葉才會與眾不同。也正是因為有了靈魂,每片楓
葉也都神似其源本的楓樹,就連脈絡也形成了一棵樹的樣子。但如果仔細看的話,
會發現,在脈絡樹之外,還存在其它的非常細的脈絡。雖然這些脈絡並不在樹上,
但他們的方向也同樣順著靈魂流淌的方向,絕不會出現可能使靈魂倒流的迴路。」 恆逸好像突然想到了什麼。
「那這些脈絡豈不是可以取代已有的脈絡,出現在脈絡樹上?」 楓茜閉上了眼睛。
「是啊,就是這樣。脈絡樹並不是唯一的。只要有一些微小的偏差,脈絡樹就
可能差之萬里,哪怕是在這同一片楓葉上。就像我們的故事,結局也不是唯一的。 只要改變一個小小的選項,故事流程可能就會被徹底扭轉。」
「真是深奧啊……」 恆逸盯著這片紅楓,若有所思地說。楓茜繼續說道。 「還不止如此呢。所有的脈絡都不會永恆存在,也不會永恆消失。不管是脈絡
樹上的脈絡,還是之外的細小脈絡,都是如此。存在的脈絡可能斷開消失,消失的
脈絡也可能再次連線。萬物皆處在永恆的變化之中,人與人之間的羈絆也是。或許
有一天,我們與大家的羈絆也會如同脈絡一樣,被無情地斬斷。或許我們也終將成
為“楓音鄉的過客”。或許這一切都會是必然,是楓樹的靈魂所決定的……」
楓茜的眼角泛起了幾滴晶瑩剔透的淚珠。恆逸看著這樣的楓茜,將她抱入懷中。
「別這樣想,楓茜。就算脈絡斷開,也有可能還會有新的脈絡樹,也還會與楓
樹的根相連。這樣的話,我們的羈絆仍然存在,只是稍微繞了一些遠路而已。無論 如何,我都不會離開你的。因為你是我窮盡一生所尋找的,我的真戀啊!」
兩人的目光對上了。楓茜幸福地笑了,把頭埋進了恆逸的懷抱。從遠方山上的 楓林中,傳來了楓的聲音。 【問題描述】 不妨假設楓葉上有
n個穴位,穴位的編號為 1 ~ n。有若干條有向的脈絡連線 著這些穴位。穴位和脈絡組成一個有向無環圖——稱之為脈絡圖(例如圖 1),穴
位的編號使得穴位 1 沒有從其他穴位連向它的脈絡,即穴位 1 只有連出去的脈絡;
由上面的故事可知,這個有向無環圖存在一個樹形子圖,它是以穴位 1為根的包含 全部n個穴位的一棵樹——稱之為脈絡樹(例如圖 2和圖
3給出的樹都是圖1給出 的脈絡圖的子圖);值得注意的是,脈絡圖中的脈絡樹方案可能有多種可能性,例 如圖2和圖 3就是圖
在這裡插入圖片描述


1給出的脈絡圖的兩個脈絡樹方案。
脈絡樹的形式化定義為:以穴位 r 為根的脈絡樹由楓葉上全部 n個穴位以及 n
-1 條脈絡組成,脈絡樹裡沒有環,亦不存在從一個穴位連向自身的脈絡,且對於 楓葉上的每個穴位 s,都存在一條唯一的包含於脈絡樹內的脈絡路徑,使得從穴位 r 出發沿著這條路徑可以到達穴位 s。
現在向脈絡圖新增一條與已有脈絡不同的脈絡(注意:連線 2個穴位但方向不
同的脈絡是不同的脈絡,例如從穴位3到4的脈絡與從4到3的脈絡是不同的脈絡, 因此,圖 1 中不能新增從 3 到 4 的脈絡,但可新增從 4
到 3 的脈絡),這條新脈絡 可以是從一個穴位連向自身的(例如,圖 1 中可新增從 4 到 4 的脈絡)。原脈絡圖
新增這條新脈絡後得到的新脈絡圖可能會出現脈絡構成的環。 請你求出添加了這一條脈絡之後的新脈絡圖的以穴位 1 為根的脈絡樹方案數。
由於方案可能有太多太多,請輸出方案數對 1,000,000,007 取模得到的結果。

Input

輸入檔案的第一行包含四個整數 n、m、x和y,依次代表楓葉上的穴位數、脈

絡數,以及要新增的脈絡是從穴位 x連向穴位y的。 接下來 m行,每行兩個整數,由空格隔開,代表一條脈絡。第 i 行的兩個整數
為ui和vi,代表第 i 條脈絡是從穴位 ui連向穴位vi的。

Output

輸出一行,為添加了從穴位 x連向穴位 y的脈絡後,楓葉上以穴位 1 為根的脈

絡樹的方案數對 1,000,000,007取模得到的結果。

Sample Input

4 4 4 3

1 2

1 3

2 4

3 2

Sample Output

3

HINT

對於所有測試資料,1 <= n <= 100000,n - 1 <= m <= min(200000, n(n – 1) / 2),

1 <= x, y, ui, vi <= n。

題解

我們考慮DAG圖上怎麼找樹
簡單地 考慮每個點的父親選誰,即有它的入度 r u [ i ] ru[i] 種選擇
於是就是 Π r u [ i ] \Pi ru[i]
進一步的 我們發現新加入的邊可能使DAG出現了環
於是單考慮每個點的父親選誰就會出現有環的情況
又發現這條邊最多會構成一個環
我們直接找這個環,其他節點照樣任選,環上節點不做操作
於是就是
Π r u [ i ] Π i n t h e r i n g r u [ j ] \frac{\Pi ru[i]}{\Pi _{in the ring}ru[j]}
記憶化記錄一下逆元即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#include<set>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline int read()
{
    int f=1,x=0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int stack[20];
inline void write(int x)
{
    if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}
const LL mod=1e9+7;
const int MAXN=100005;
const int MAXM=200005;
struct node{int x,y,next;}a[MAXM];int len,last[MAXN];
void ins(int x,int y){len++;a[len].x=x;a[len].y=y;a[len].next=last[x];last[x]=len;}
LL ru[MAXN],inv[MAXN],temp,ans;
LL pow_mod(LL a,LL b)
{
    LL ret=1;
    while(b)
    {
        if(b&1)ret=ret*a%mod;
        a=a*a%mod;b>>=1;
    }
    return ret;
}
bool ok[MAXN];LL g[MAXN];
LL dfs(int x,int ed)
{
    if(x==1)return 0;
    if(ok[x])return g[x];
    if(x==ed)return inv[x];
    for(int k=last[x];k;k=a[k].next)
    {
        int y=a[k].y;
        LL re=dfs(y,ed);
        g[x]=(g[x]+inv[x]*re)%mod;
    }
    ok[x]=1;return g[x];
}
int n,m,u1,u2;
int main()
{
    n=read();m=read();u1=read();u2=read();
    ins(u1,u2);
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read();
        ins(x,y);ru[y]++;
    }
    ru[u2]++;
    for(int i=1;i<=n;i++)inv[i]=pow_mod(ru[i],mod-2);
    LL s1=1;
    for(int i=2;i<=n;i++)s1=s1*ru[i]%mod;
    LL s2=dfs(u2,u1);
    s1=(s1-s1*s2%mod+mod)%mod;
    pr2(s1);
    return 0;
}