【题解/总结】两双手(格路问题)/格路问题的某一本质

【题解】两双手(格路问题)

题目大意:求从\((0,0)\)到\((Ex,Ey)\)不经过给定障碍点的方案数。你每次移动只能是加上向量\(e_1\)或者向量\(e_2\),\(e_1,e_2\)中的基底都是整数。

考虑转化一下这个问题,从某个点走到在他右上角的某点需要加上\(ae_1+be_2\),这样我们就可以解出\(a,b\)。我们把\((a,b)\)拿出来建立新的坐标系,就变成了简单的格路问题了。结合【题解】CF559C C. Gerald and Giant Chess(容斥+格路问题)就可以直接做了。当不存在\((a,b)\)是非负整数解时,可以把这个点删掉。

考虑为什么可以这样解出两个值\((a,b)\)转化,只能在这道题里用吗?实际上,格路问题可以抽象成这样一种问题:

你有两种元素,每种元素每次可以增加一一次只能加一种元素,元素之间互相独立。现在要你从\((0,0)\)加到\((n,m)\),问你多少组方案。方案的本质是对于加元素的操作构成的合法序列的总数。

用序列的角度看问题,?有\(a_i\)种\(i\)元素,你要好好排列出\(\sum a_i\)长度的序列,问这些序列不同的分布。这就可以拓展为多维的问题。

这应该是此类格路问题的本质。

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;  typedef long long ll;
inline int qr(){
      register int ret=0,f=0;
      register char c=getchar();
      while(c<48||c>57)f|=c==45,c=getchar();
      while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
      return f?-ret:ret;
}
int n,A1,A2,B1,B2;
const int maxn=5e2+5;
const int mod=1e9+7;
typedef pair<int,int> P;
P data[maxn];
int jc[1000001],inv[1000001],cnt,dp[maxn];

inline int ksm(const int&ba,const int&p){
      int ret=1;
      for(int t=p,b=ba%mod;t;t>>=1,b=1ll*b*b%mod)
        if(t&1) ret=1ll*ret*b%mod;
      return ret;
}

inline void pre(const int&n){
      *jc=*inv=1;
      for(int t=1;t<=n;++t) jc[t]=1ll*jc[t-1]*t%mod;
      inv[n]=ksm(jc[n],mod-2);
      for(int t=n-1;t;--t)  inv[t]=1ll*inv[t+1]*(t+1)%mod;
}

inline bool get(P&s){
      int x=s.first,y=s.second;
      int a=(B2*x-B1*y)/(A1*B2-A2*B1);
      int b=(A2*x-A1*y)/(A2*B1-A1*B2);
      s=(pair<int,int>){a,b};
      return a*A1+b*B1==x&&a*A2+b*B2==y&&a>=0&&b>=0;
}

inline int c(const int&n,const int&m){return n<m?0:1ll*jc[n]*inv[m]%mod*inv[n-m]%mod;}
inline int grid(const int&x,const int&y){return c(x+y,x);}
int main(){
      int f=qr(),g=qr();
      data[++cnt]=(pair<int,int>){f,g}; n=qr();
      A1=qr(); A2=qr();
      B1=qr(); B2=qr();
      if(!get(data[1])) return !puts("0");
      pre(1e6);
      for(int t=1,t1,t2;t<=n;++t){
        t1=qr(); t2=qr();
        data[++cnt]=(pair<int,int>){t1,t2};
        if(!(get(data[cnt])&&data[cnt]<=data[1])) --cnt;
      }
      sort(data+1,data+cnt+1);
      for(int t=1;t<=cnt;++t){
        dp[t]=grid(data[t].first,data[t].second);
        for(int i=1;i<t;++i)
          dp[t]=(dp[t]-1ll*dp[i]*grid(data[t].first-data[i].first,data[t].second-data[i].second)%mod+mod)%mod;
      }
      printf("%d\n",dp[cnt]);
      return 0;
}

原文地址:https://www.cnblogs.com/winlere/p/11566828.html

时间: 2024-08-04 00:25:08

【题解/总结】两双手(格路问题)/格路问题的某一本质的相关文章

Bzoj4767 两双手

Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 553  Solved: 160 Description 老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式.老W下棋时觉得无聊,便 决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从(u,v)移动到(u+Ax,v+Ay)而另一双手能让 马从(u,v)移动到(u+Bx,v+By).小W看见老W的下棋方式,觉得非常有趣,他开始思考一个问题:假设棋盘是个无限 大的

[BZOJ 4767]两双手(组合数学+Dp)

Description 老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式.老W下棋时觉得无聊,便 决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从(u,v)移动到(u+Ax,v+Ay)而另一双手能让 马从(u,v)移动到(u+Bx,v+By).小W看见老W的下棋方式,觉得非常有趣,他开始思考一个问题:假设棋盘是个无限 大的二维平面,一开始马在原点(0,0)上,若用老W的两种方式进行移动,他有多少种不同的移动方法到达点(Ex,Ey )呢?两种移动方法不

bzoj4767两双手 容斥+组合

4767: 两双手 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 684  Solved: 208[Submit][Status][Discuss] Description 老W是个棋艺高超的棋手,他最喜欢的棋子是马,更具体地,他更加喜欢马所行走的方式.老W下棋时觉得无聊,便 决定加强马所行走的方式,更具体地,他有两双手,其中一双手能让马从(u,v)移动到(u+Ax,v+Ay)而另一双手能让 马从(u,v)移动到(u+Bx,v+By).小W看见老

BZOJ 4767 两双手

题解: 发现这种题目虽然可以想出来,但磕磕碰碰得想挺久的 根据数学可以知道组成方案是唯一的(集合) 然后发现每个使用的大小可能是接近n^2的 直接dp(n^4)是过不了的 那么先观察观察 我们可以把每个障碍点的表示也搞出来 这样就变成了一张网格图求起点到终点的方案数 然后考虑一下容斥,枚举第一个经过的障碍点是谁(之后就随便走了) 然后发现做这个的时候在不断递归 那可以直接按照x,y排个序 依次递推过去 原文地址:https://www.cnblogs.com/yinwuxiao/p/888387

[leetcode题解]01两数之和

给定一个整数数组 nums?和一个目标值 target,请你在该数组中找出和为目标值的那?两个?整数,并返回他们的数组下标. 你可以假设每种输入只会对应一个答案.但是,你不能重复利用这个数组中同样的元素. 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 分析 关键字:数组.查找.下标. 由于数组是无序的,查找必须要遍历,不能用二分查找,时间复杂度一般最小为O(n). 暴力解法:遍历

LeetCode 题解 | 1. 两数之和

题目描述: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用. 示例: 给定 nums = [2, 7, 11, 15], target = 9 因为 nums[0] + nums[1] = 2 + 7 = 9 所以返回 [0, 1] 方法一.暴力解法: 暴力法很简单,遍历每个元素 ,并查找是否存在一个值与 相等的目标元素. class Solution { public: vector<int> twoSum(vect

【bzoj4676】 两双手

http://www.lydsy.com/JudgeOnline/problem.php?id=4767 (题目链接) 题意 求在网格图上从$(0,0)$走到$(n,m)$,其中不经过一些点的路径方案数. Solution 转换一下就变成了题意中的模型.我们将网格上的起点和不允许经过的点全部看做一类点,用$f[i]$表示从第$i$个点不经过其它点到达终点的路径条数,用$D(i,j)$表示个点之间的路径条数,$T$表示终点.转移: \begin{aligned}  f[i]=D(i,T)-\sum

bzoj 4767 两双手 - 动态规划 - 容斥原理

题目传送门 传送门I 传送门II 题目大意 一个无限大的棋盘上有一只马,设马在某个时刻的位置为$(x, y)$, 每次移动可以将马移动到$(x + A_x, y + A_y)$或者$(x + B_x, y + B_y)$.棋盘上有$n$个禁止位置不能经过,问马从$(0, 0)$走到$(E_x, E_y)$的方案数. 容斥是显然的. 每确定经过$k$个禁止位置的方案数的容斥系数是$(-1)^{k}$. 考虑带上容斥系数来动态规划, 注意到去掉重复的禁止位置后,$(0, 0), (E_x, E_y)

uva11624 - Fire! 两次bfs

题目链接 Problem B: Fire! Joe works in a maze. Unfortunately, portions of the maze have caught on fire, and the owner of the maze neglected to create a fire escape plan. Help Joe escape the maze. Given Joe's location in the maze and which squares of the