先来看看它的祖宗
大意:
给定h ∗ w的矩阵,上面有n个黑点,其余的都是白点。每次只能向下走或向右走,问从(1,1) 走到 (h,w) 不经过黑点的路径有多少条,答案对1e9+7取模。n<=2000,h,w<=2e5
思路:给的矩阵有点大,所以我们没办法按常规思路n^2解决。又注意到黑点的个数其实不多,所以我们不妨以其为对象进行dp。显然的,把点按横坐标排序,我们设dp[i]表示走到第i个黑点且中间没有经过其它黑点的方案数,那么这样就能支撑n^2的遍历了。
不考虑黑点的话,(1,1)->(i,j)的方案数是C(i+j-2,i-1),那么只要中间做一下容斥就好了
对于点j<i,j的横坐标不大于x的横坐标,如果j的纵坐标大于x的纵坐标,显然是没有从j走到i的方案的,所以这里我们不用容斥。否则减去dp[j]*(j->i的方案数)(因为每一个点的dp值都是代表其第一次被走到的方案数,不会包括其它黑点,所以这样是不会多减的),j->i的方案数用上述做法即得。
这样就能做完这题了。
dp就是这样,看看思路好像也就这么一回事,可我就是想不到。。。(泪
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const ll N=2e5+10;
const ll mod=1e9+7;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1) ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
ll inv(ll x)
{
return ksm(x,mod-2);
}
ll p[N],pp[N];
void init()
{
p[0]=1;
for(ll i=1;i<=200000;++i) p[i]=p[i-1]*i%mod;
pp[200000]=inv(p[200000]);
for(ll i=200000-1;i>=0;--i) pp[i]=pp[i+1]*(i+1)%mod;
}
ll n,m,h,w;
struct ty
{
ll x,y;
}mas[2010];
bool cmp(ty a,ty b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
ll C(ll n,ll m)
{
if(n<m) return 0;
return p[n]*pp[m]%mod*pp[n-m]%mod;
}
ll dp[2010];
void solve()
{
init();
cin>>h>>w>>m;
for(int i=1;i<=m;++i)
{
cin>>mas[i].x>>mas[i].y;
}
mas[m+1].x=h,mas[m+1].y=w;
sort(mas+1,mas+1+m,cmp);
for(int i=1;i<=m+1;++i)
{
dp[i]=C(mas[i].x-1+mas[i].y-1,mas[i].x-1);
for(int j=1;j<i;++j)
{
if(mas[j].y>mas[i].y) continue;
dp[i]=((dp[i]-dp[j]*C(mas[i].x-mas[j].x+mas[i].y-mas[j].y,mas[i].x-mas[j].x)%mod)%mod+mod)%mod;
}
}
// for(int i=1;i<=m+1;++i) cout<<dp[i]<<' ';
// cout<<endl;
cout<<dp[m+1]<<endl;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
solve();
return 0;
}
然后就是牛客那道了
大意:
算是上一题的弱化版本,黑点数很少,所以其实也可以状压去做,然后就遍历一下好梦点,加一下方案数就可以了。
code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define endl '\n'
const ll N=2e5+10;
const ll mod=1e9+7;
ll ksm(ll x,ll y)
{
ll ans=1;
while(y)
{
if(y&1) ans=ans*x%mod;
x=x*x%mod;
y>>=1;
}
return ans;
}
ll inv(ll x)
{
return ksm(x,mod-2);
}
ll p[N],pp[N];
void init()
{
p[0]=1;
for(ll i=1;i<=200000;++i) p[i]=p[i-1]*i%mod;
pp[200000]=inv(p[200000]);
for(ll i=200000-1;i>=0;--i) pp[i]=pp[i+1]*(i+1)%mod;
}
ll n,m,h,w;
struct ty
{
ll x,y;
}mas[2010];
bool cmp(ty a,ty b)
{
if(a.x==b.x) return a.y<b.y;
return a.x<b.x;
}
ll C(ll n,ll m)
{
if(n<m) return 0;
return p[n]*pp[m]%mod*pp[n-m]%mod;
}
ll dp[2010];
void solve()
{
init();
cin>>n>>m;
for(int i=1;i<=m;++i)
{
cin>>mas[i].x>>mas[i].y;
}
sort(mas+1,mas+1+m,cmp);
for(int i=1;i<=m+1;++i)
{
dp[i]=C(mas[i].x-1+mas[i].y-1,mas[i].x-1);
for(int j=1;j<i;++j)
{
if(mas[j].y>mas[i].y) continue;
dp[i]=((dp[i]-dp[j]*C(mas[i].x-mas[j].x+mas[i].y-mas[j].y,mas[i].x-mas[j].x)%mod)%mod+mod)%mod;
}
}
ll sum=0;
for(int i=1;i<=n;++i)
{
ll x=i;ll y=n-i+1;
ll gt=C(x+y-2,x-1);
for(int j=1;j<=m;++j)
{
if(mas[j].x>x||mas[j].y>y) continue;
gt=((gt-dp[j]*C(x-mas[j].x+y-mas[j].y,x-mas[j].x)%mod)%mod+mod)%mod;
}
sum=(sum+gt)%mod;
}
cout<<sum<<endl;
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
solve();
return 0;
}