计数问题一直是让我头疼的问题啊…最近开始整理相关的问题。
NamoCamp
每日一题
#467. 路径计数2
有一个 n∗n 的网格,有些格子是可以通行的,还有 m 个格子是障碍。
一开始你在左上角的位置,你可以每一步往下或者往右走,问有多少种走到右下角的方案。
由于答案很大,输出对 1e9+7取模的结果。
输入格式
第一行两个数字 n, m。
接下来 m 行,每行 2 个整数 xi,yi
,代表第 i 个障碍的坐标。
输出格式
一个数,表示答案。
样例输入
样例输出
数据规模
所有数据保证 1≤n≤106,1≤m≤3000,1≤xi,yi≤n
首先我们观察到数据范围不适合做n*n的DP,因此我们寻找突破口m=3000,设状态DP[i]
表示从(1,1)到第i个障碍,其中不经过其他任何障碍的方案数.因此对于第i个障碍的转移需要其他所有状态中横纵坐标都小于第i个障碍的点来进行转移。
我们可以用BFS或者记忆化搜索来完成状态的转移:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const int N=6010,M=2000010,mod=1e9+7; pair<int,int> pos[N]; int f[N],fact[M],inv[M],n,m; int C(int n,int m){ if(n<m) return 0; else if(n==m||m==0) return 1; return (LL)fact[n]*inv[n-m]%mod*inv[m]%mod; } void init(){ fact[0]=1; rep(i,1,M-10) fact[i]=(LL)fact[i-1]*i%mod; inv[M-10]=fpower(fact[M-10], mod-2,mod); per(i,M-11,1) inv[i]=(LL)inv[i+1]*(i+1)%mod; inv[0]=1; } int dfs(int u){ if(f[u]!=-1) return f[u]; int res=0; for(int i=1;i<=m;++i){ if(pos[i].x<=pos[u].x&&pos[i].y<=pos[u].y&&i!=u) res=(res+(LL)dfs(i)*C(pos[u].x-pos[i].x+pos[u].y-pos[i].y,pos[u].x-pos[i].x)%mod)%mod; } res=(((LL)C(pos[u].x-1+pos[u].y-1,pos[u].x-1)-res)%mod+mod)%mod; return f[u]=res; }
void solve(){ n=read(),m=read(); rep(i,1,m) pos[i].x=read(),pos[i].y=read(); pos[++m].x=n,pos[m].y=n; memset(f,-1,sizeof f); print(dfs(m)); }
|