最近遇到的各种DP 2.0

3 篇文章 0 订阅
题目链接

wls的每日一题,容斥板子。

http://oj.daimayuan.top/problem/467

题意

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UD4GqIIZ-1647916845453)(C:\Users\xi2001\AppData\Roaming\Typora\typora-user-images\image-20220322100240751.png)]

思路

n = 1 0 6 n = 10^6 n=106 , 显然我们不能依照 n n n来做,考虑根据障碍物 m m m进行转移。

我们记录 d p [ i ] dp[i] dp[i] 为 从 位置 ( 1 , 1 ) (1,1) 11到第$ i $个障碍物的合法走法。

记第 i i i个障碍物的位置是 ( x i , y i ) (x_i,y_i) (xi,yi) ,

1.当第 i i i个障碍物前没有障碍物时,显然有:

d p [ i ] dp[i] dp[i] = C x i + y i − 2 x i − 1 C_{x_i+y_i-2}^{x_i-1} Cxi+yi2xi1

2.假设第 i i i个障碍物前有一个障碍物 j j j,那么我们就减去障碍物 j j j对答案的贡献:

d p [ i ] dp[i] dp[i] = d p [ i ] dp[i] dp[i] - d p [ j ] dp[j] dp[j] * (从 j j j号障碍物到 i i i号障碍物的走法)

d p [ i ] = d p [ i ] − ∑ j = 1 i − 1 d p [ j ] ∗ C x i + y i − x j − y j x i − y i dp[i]= dp[i] - \sum_{j=1}^{i-1} dp[j] * C_{x_i+y_i-x_j-y_j}^{x_i-y_i} dp[i]=dp[i]j=1i1dp[j]Cxi+yixjyjxiyi
= C x i + y i − 2 x i − 1 − ∑ j = 1 i − 1 d p [ j ] ∗ C x i + y i − x j − y j x i − y i ( 其 中 x j < = x i , y j < = y i ) = C_{x_i+y_i-2}^{x_i-1} - \sum_{j=1}^{i-1} dp[j] * C_{x_i+y_i-x_j-y_j}^{x_i-y_i} ( 其中x_j<=x_i , y_j<=y_i ) =Cxi+yi2xi1j=1i1dp[j]Cxi+yixjyjxiyi(xj<=xi,yj<=yi)

如图 , d p [ i ] dp[i] dp[i] = 总的走法 - 蓝色区域走法*绿色区域走法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-U2RVS0OC-1647916845454)(C:\Users\xi2001\AppData\Roaming\Typora\typora-user-images\image-20220322103540804.png)]

我想这个题的时候曾经有一个疑问

j j j号障碍物到 i i i号障碍物的走法” 这里可能会经过其他障碍物,不会造成重复吗?

想想其实是不会的,我们假设 j j j i i i 中间插着一个障碍物 z z z
那么一定不会存在一条 j − − > z − − > i j-->z-->i j>z>i 的路线被统计两次,
因为 z z z会先于 i i i被访问,而 d p [ z ] dp[z] dp[z] 中一定不存在经过j的情况。

3.关于答案统计:

这个简单,创造第 n + 1 n+1 n+1个障碍物在 ( n , n ) (n,n) (n,n)处 , 答案即 d p [ n + 1 ] dp[n+1] dp[n+1]

代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e6+100;
const int M = 3030;
const int mod = 1e9+7;
int fac[N],inv[N];
int dp[M];
struct node{
    int x;
    int y;
    bool operator< (node B)const{
        if(x==B.x) return y<B.y;
        return x<B.x;
    }
};
vector<node> v;
int ksm(int a,int b,int p){
    int ans = 1;
    while(b){
        if(b&1) ans = ans*a%p;
        a = a*a%p;
        b >>= 1;
    }
    return ans%p;
}
void pre(){
    const int mx = 2e6;
    fac[0] = 1;
    for(int i=1;i<=mx;i++){
        fac[i] = fac[i-1]*i%mod;
    }
    inv[mx] = ksm(fac[mx],mod-2,mod)%mod;  // 逆元
    for(int i=mx-1;i>=0;i--){
        inv[i] = inv[i+1]*(i+1)%mod;
    }
}
int C(int n,int m){
    return fac[n]*inv[n-m]%mod*inv[m]%mod;   // 组合数
}
signed main(){
    ios::sync_with_stdio(false);
    pre();    // 预处理逆元和累乘
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int x,y;
        cin>>x>>y;
        v.push_back({x,y});
    }
    v.push_back({n,n});    // 创造第n+1个障碍物在(n,n)处 
    sort(v.begin(),v.end());
    for(int i=0;i<v.size();i++){
        node now = v[i];
        dp[i] = C(now.x+now.y-2,now.x-1)%mod;
    }
    for(int i=0;i<v.size();i++){
        node now = v[i];
        for(int j=0;j<i;j++){
            if(v[j].x<=v[i].x&&v[j].y<=v[i].y){   // 保证j在i前面
                node tmp = v[j];
                int cnt = C(now.x-tmp.x+now.y-tmp.y,now.y-tmp.y)%mod;
                dp[i] = (dp[i] - cnt*dp[j]%mod+mod)%mod;
            }
        }
    }
    cout<<dp[v.size()-1]<<endl;
}

上课了,待更

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值