首页 > 其他分享 >bzoj4767 两双手

bzoj4767 两双手

时间:2024-08-05 21:05:28浏览次数:7  
标签:bzoj4767 两双手 int ay ax stepx stepy define

题目传送

容斥思想的一道好题。

首先我们可以很轻松的将使用 \(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;
}

标签:bzoj4767,两双手,int,ay,ax,stepx,stepy,define
From: https://www.cnblogs.com/ziyistudy/p/18344055

相关文章