【CodeChef】KNGHTMOV(方案数DP)
题意:
考虑一张无限大的方格棋盘。我们有一个“骑士”,它必须从(0,0)格开始,按照如下规则,移动至(X,Y)格:每一步,它只能从(u,v)格移动至(u+Ax,v+Ay)或者(u+Bx,v+By)。注意,该规则可能不同于国际象棋中骑士的移动规则。
此外,棋盘上有K个障碍格,骑士不能进入这些格子。
你的任务是计算骑士有多少种到达指定位置的方案。我们认为两种方案不同,当且仅当它们的步数不同,或者存在某个i使得两种方案中,骑士在第i步到达的格子不同。注意,骑士在到达(X,Y)格后还可能继续移动。
对每组数据,输出移动方案数模1000000007(10^9+7)的值。如果有无穷多种方案,输出-1.
所有坐标的绝对值不超过500
(0,0)不是障碍格
(X,Y)不是障碍格
1<=T<=5
对于40%的数据,0<=K<=5
对于100%的数据,0<=K<=15
思路:


向量贡献部分的dp
dp[i][j]表示走i步,当前在位置j的方案数,因为所有向量都已经被压缩成了1维
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll;
typedef unsigned int uint;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef vector<int> VI;
#define fi first
#define se second
#define MP make_pair
#define N 1100000
#define M 1100
#define eps 1e-8
#define MOD 1000000007
#define pi acos(-1) class Point
{
public:
int x,y;
}; ll dp[M*+][M*+];
bool vis[M*+][M*+];
bool flag[M*+];
ll fac[N],inv[N];
Point b[],A,B,d;
ll f[];
int K; int read()
{
int v=,f=;
char c=getchar();
while(c<||<c) {if(c=='-') f=-; c=getchar();}
while(<=c&&c<=) v=(v<<)+v+v+c-,c=getchar();
return v*f;
} void add(ll &a,ll &b)
{
if(a==-||b==-) a=-;
else a=(a+b)%MOD;
} bool depend(Point &a,Point &b) //线性相关
{
//printf("%d %d %d %d\n",a.x,b.y,a.y,b.x);
return a.x*b.y==a.y*b.x;
} bool operator < (Point &a,Point &b)
{
return a.x+a.y<b.x+b.y;
} void swap_xy()
{
swap(A.x,A.y);
swap(B.x,B.y);
swap(d.x,d.y);
for(int i=;i<=K;i++) swap(b[i].x,b[i].y);
} int solve_depend()
{
//printf("YES\n");
//printf("%d %d\n",d.x,d.y);
if(!depend(A,d)||!depend(B,d)) return ;
//A,B中可能有0
if(!A.x&&!A.y&&!B.x&&!B.y)
{
if(!d.x&&!d.y) return -;
return ;
}
if(!A.x)
{
if(A.y) swap_xy();
else if(B.x) swap(A,B);
else
{
swap(A,B);
swap_xy();
}
}
memset(dp,,sizeof(dp));
memset(vis,,sizeof(vis));
memset(flag,,sizeof(flag));
for(int i=;i<=K;i++)
if(depend(b[i],A)&&depend(b[i],B)) flag[b[i].x+M]=;
if((!A.x&&!A.y)||(!B.x&&!B.y)) dp[][M]=-;
else dp[][M]=;
vis[][M]=true;
ll ans=;
for(int i=;i<M*;i++)
{
for(int j=-M;j<=M;j++)
{
int v=j+M;
if(!flag[v]) //无障碍
{
if(!vis[i][v]) continue;
if(j>||j<-||i>) dp[i][v]=-; //若能绕回dest必定有无数种,若回不来那-1也没用
if(v+A.x>=&&v+A.x<=*M) //A
{
add(dp[i+][v+A.x],dp[i][v]);
vis[i+][v+A.x]=true;
}
if(A.x!=B.x&&v+B.x>=&&v+B.x<=*M) //B
{
add(dp[i+][v+B.x],dp[i][v]);
vis[i+][v+B.x]=true;
}
}
}
add(ans,dp[i][d.x+M]);
}
return ans;
} bool change(Point &p)
{
int k=A.y*B.x-A.x*B.y;
int a=p.y*B.x-p.x*B.y;
int b=p.x*A.y-p.y*A.x;
//printf("%d %d %d\n",k,a,b);
if(a%k||b%k) return false;
p.x=a/k; p.y=b/k;
return true;
} ll C(int x,int y)
{
return fac[x]*inv[y]%MOD*inv[x-y]%MOD;
} ll calc(Point &a,Point &b)
{
int x=b.x-a.x;
int y=b.y-a.y;
if(x<||y<) return ;
return C(x+y,x);
} int solve_independ()
{
if(!change(d)) return ; //终点在变换后不是整点
if(d.x<||d.y<) return ; //终点在变换后不是整点
int n=;
for(int i=;i<=K;i++) //障碍变换
if(change(b[i]))
if(b[i].x>=&&b[i].y>=) b[++n]=b[i];
sort(b+,b+n+); //障碍排序
Point O=(Point){,};
ll ans=calc(O,d); for(int i=;i<=n;i++)
{
f[i]=calc(O,b[i]);
for(int j=;j<i;j++)
f[i]=(f[i]-f[j]*calc(b[j],b[i])%MOD)%MOD;
ans=(ans-f[i]*calc(b[i],d)%MOD)%MOD;
}
ans=(ans%MOD+MOD)%MOD;
return ans;
} int solve()
{
if(depend(A,B)) return solve_depend();
else return solve_independ();
} int main()
{
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
fac[]=;
for(int i=;i<=N-;i++) fac[i]=fac[i-]*i%MOD;
inv[]=inv[]=;
for(int i=;i<=N-;i++) inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
for(int i=;i<=N-;i++) inv[i]=inv[i-]*inv[i]%MOD;
int cas;
scanf("%d",&cas);
while(cas--)
{
scanf("%d%d%d",&d.x,&d.y,&K);
scanf("%d%d%d%d",&A.x,&A.y,&B.x,&B.y);
for(int i=;i<=K;i++) scanf("%d%d",&b[i].x,&b[i].y);
printf("%d\n",solve());
}
return ;
}
【CodeChef】KNGHTMOV(方案数DP)的更多相关文章
- 【CF559C】 Gerald and Giant Chess(计数,方案数DP,数论)
题意:给出一个棋盘为h*w,现在要从(1,1)到(h,w),其中有n个黑点不能走,问有多少种可能从左上到右下 (1 ≤ h, w ≤ 105, 1 ≤ n ≤ 2000),答案模10^9+7 思路:从 ...
- bzoj1708[Usaco2007 Oct]Money奶牛的硬币(背包方案数dp)
1708: [Usaco2007 Oct]Money奶牛的硬币 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 763 Solved: 511[Submi ...
- Codeforces 509F Progress Monitoring:区间dp【根据遍历顺序求树的方案数】
题目链接:http://codeforces.com/problemset/problem/509/F 题意: 告诉你遍历一棵树的方法,以及遍历节点的顺序a[i],长度为n. 问你这棵树有多少种可能的 ...
- 背包DP 方案数
题目 1 P1832 A+B Problem(再升级) 题面描述 给定一个正整数n,求将其分解成若干个素数之和的方案总数. 题解 我们可以考虑背包DP实现 背包DP方案数板子题 f[ i ] = f[ ...
- 洛谷P1108 低价购买[DP | LIS方案数]
题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它 ...
- Codeforces 461B. Appleman and Tree[树形DP 方案数]
B. Appleman and Tree time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- P2347 砝码称重-DP方案数-bitset
P2347 砝码称重 DP做法 : 转化为 01背包. 进行方案数 更新.最后统计种类. #include<bits/stdc++.h> using namespace std; #def ...
- HDU 1208 Pascal's Travels 经典 跳格子的方案数 (dp或者记忆化搜索)
Pascal's Travels Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u Su ...
- ZOJ - 2402 DP方案数
题意:给出m,序列第i位是第i-1位的至少2倍大,的求长度为n且每一位范围均在1-m的序列方案数 对求方案数做不到信手拈来的感觉,需要加强 用简单的预处理和最优子结构能优化到很不错的效率了 #incl ...
随机推荐
- AJPFX理解反射及反射的应用
怎么理解反射,反射的应用 反射就是把Java类中的各种成分映射成相应的Java类. 一般情况下我们要解决某个问题,先找到相关的类,创建该类的对象,然后通过该对象调用对应的方 ...
- CF949A/950C Zebras
思路: 贪心乱搞. 实现: #include <bits/stdc++.h> using namespace std; vector<vector<int>> v; ...
- css的过渡背景色
css3新增的渐变背景色属性用法 原博客地址:http://caibaojian.com/css3-background-gradient.html
- 有关HTML版本
先说说HTML的简史:从HTML1.0~2.0(1989~1991)>HTML3(1995)>HTML4(1998)>HTML4.01(1999)>XHTML1.0(2001) ...
- mysql 插入多条记录,重复值不插入
只去除主键与唯一索引的字段,字段为null时 是可以重复插入的domo: insert ignore into table_name(email,phone,user_id) values('test ...
- 关于NSCELL
作为一个初学者,我一直很弄不明白NSCell的子类,比如,NSButtonCell,NSImageCell及其对应的控件之间的关系.今天,在做一个TableView实现的时候,我终于开始有点悟了——好 ...
- codeforces_D. Social Circles
http://codeforces.com/contest/1060/problem/D 题意: n个客人,每个客人希望自己左边空li个座位,右边空ri个座位,可以形成任意个圆,问最少多少个座位. 思 ...
- select 修改选中时候的默认默认样式 outline:none 把系统的线关了 然后自己再border一下
chrome 查看样式的时候默认没有 focus的样式,可以把选择器开开select 修改选中时候的默认默认样式 outline:none 把系统的线关了 然后自己再border一下input:foc ...
- ztree 样式修改 white-space: nowrap; 后 下划线要是跟上的话 宽度 width 要 auto 就自动更新了
width:auto; border-bottom:1px solid #ccc; height:30px; display: inline-block;white-space: nowrap;
- 转:函数调用的区别:_cdecl以及_stdcall
函数调用的几个概念:_stdcall,_cdecl.... 1._stdcall是Pascal程序的缺省调用方式,通常用于Win32 Api中,函数采用从右到左的压栈方式,自己在退出时清空堆栈.VC将 ...