bzoj 4011: [HNOI2015]落忆枫音 递推

来源:互联网 发布:漫画软件免费下载 编辑:程序博客网 时间:2024/05/24 13:28

       计数dp(递推)裸题(跟zj的题真心不能比啊)。。。

       假设没有那个加边。那么显然答案就是所有点的入度相乘的结果(不包括1),显然每个点都可以随意选择一个入边,那么由于原图是DAG,因此选完n-1条边之后一定连通且无环,因此必然合法。

       一开始斯波看错题以为是随意加一条边然后统计总方案数

       那么加入S->T这条边之后,不妨仍然按照上述方法直接求答案;然后考虑产生环的不合法的方案。显然环中必有S->T这条边,以及T->S的一条路径。如果枚举这条路径,那么一条路径的贡献就是除了这条路径以外的点的入度的积。令f[x]表示T->x的答案,那么根据定义有f[y]=Σf[x]/dgree[y],(x,y)∈E。按topo序dp即可。

AC代码如下:

#include<iostream>#include<cstdio>#define mod 1000000007#define ll long long#define N 100005using namespace std;int n,m,sta,gol,tot,fst[N],pnt[N<<1],nxt[N<<1],dgr[N],num[N],inv[N],h[N],f[N];int read(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }return x;}void add(int x,int y){pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;}int main(){n=read(); m=read(); sta=read(); gol=read(); int i,x,y;inv[0]=inv[1]=1;for (i=2; i<=n; i++) inv[i]=mod-(ll)inv[mod%i]*(mod/i)%mod;for (i=1; i<=m; i++){x=read(); y=read(); add(x,y);dgr[y]++;}for (i=1; i<=n; i++) num[i]=dgr[i];dgr[gol]++; int ans=1;for (i=2; i<=n; i++) ans=(ll)ans*dgr[i]%mod;if (gol==1){ printf("%d\n",ans); return 0; }f[gol]=ans;int head=0,tail=0;for (i=1; i<=n; i++) if (!dgr[i]) h[++tail]=i;while (head<tail){x=h[++head]; f[x]=(ll)f[x]*inv[dgr[x]]%mod;if (x==sta) break;for (i=fst[x]; i; i=nxt[i]){y=pnt[i]; num[y]--;f[y]+=f[x]; if (f[y]>=mod) f[y]-=mod;if (!num[y]) h[++tail]=y;}}printf("%d\n",(ans-f[sta]+mod)%mod);return 0;}

by lych

2016.5.2

0 0
原创粉丝点击