window.cnblogsConfig = {//可以放多张照片,应该是在每一个博文上面的图片,如果是多张的话,那么就随机换的。 homeTopImg: [ "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png", "https://cdn.luogu.com.cn/upload/image_hosting/clcd8ydf.png" ], }

bzoj4767 两双手

题目传送

容斥思想的一道好题。

首先我们可以很轻松的将使用 \(A,B\) 两种移动的次数从而到达一个点通过二元一次方程解出。不妨设分别为 \(x,y\) 步,这样一来,如果我们不考虑禁止点,方案为 \(\binom{x+y}{x}\) 。则我们现将给出的禁止点转换为步数 \((x,y)\),并排序。

但这样显然多算了经过禁止点的情况。发现经过的禁止点一定再该禁止点的左下方(感性理解一下),不妨设 \(dis_{i,j}\) 为禁止点 \(i\)\(j\) 的方案数,\(f_i\) 为到达禁止点 \(i\) 且以前没有到达过禁止点的方案数(这是一个常见的状态设计)。则不难发现转移 \(f_i=\binom{x_i+y_i}{x_i} - \sum_{j=1}^{i-1} f_j \cdot dis_{i,j}\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define eb emplace_back
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll MOD=1e9+7;
// head
const int N=2e6+5;
struct node{int x,y;};
bool cmp(node p,node q) {if(p.x!=q.x) return p.x<q.x;return p.y<q.y;}
int ex,ey,n;
int ax,ay,bx,by;
vector<node> point;
void change(int &x,int &y)
{
    int stepy=(ay*x-ax*y)/(ay*bx-ax*by),stepx;
    if(ax==0&&ay==0) {x=-1,y=-1;return ;}
    if(ax!=0) stepx=(x-bx*stepy)/ax;
    else stepx=(y-by*stepy)/ay;
    if(x!=ax*stepx+bx*stepy||y!=ay*stepx+by*stepy) x=-1,y=-1;
    else x=stepx,y=stepy;
}
int fac[N],inv[N];
int fast_pow(int bas,int ind)
{
    int ans=1;
    while(ind)
    {
        if(ind&1) ans=ans*bas%MOD;
        bas=bas*bas%MOD;
        ind>>=1; 
    }
    return ans;
}
void init()
{
    fac[0]=1;
    for(int i=1;i<N;i++) fac[i]=fac[i-1]*i%MOD;
    inv[N-1]=fast_pow(fac[N-1],MOD-2);
    for(int i=N-2;i>=0;i--) inv[i]=inv[i+1]*(i+1)%MOD;
}
int C(int n,int k) {return (n<k?0:fac[n]*inv[k]%MOD*inv[n-k]%MOD);}
int dp[N];
signed main() 
{
    cin.tie(nullptr);
    ios::sync_with_stdio(false);

    init();

    cin>>ex>>ey>>n;
    cin>>ax>>ay>>bx>>by;
    change(ex,ey);point.pb({ex,ey});
    for(int i=0;i<n;i++) {int x,y;cin>>x>>y;change(x,y);if(x!=-1&&y!=-1&&x<=ex&&y<=ey)point.pb({x,y});}
    sort(all(point),cmp);
    for(int i=0;i<point.size();i++){
        dp[i]=C(point[i].x+point[i].y,point[i].x);
        for(int j=0;j<i;j++){
            (dp[i]-=dp[j]*C(point[i].x-point[j].x+point[i].y-point[j].y,point[i].x-point[j].x)%MOD-MOD)%=MOD;
        }
    }
    cout<<dp[point.size()-1]<<endl;
}
posted @ 2024-08-05 21:05  ziyistudy  阅读(24)  评论(0)    收藏  举报