【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 ...
随机推荐
- 转】Nodejs对MongoDB模糊查询
原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/page/4/ 感谢! Posted: Jul 1, 2013 Tag ...
- 转】在Ubuntu中安装Redis
不多说,直接上干货! 原博文出自于: http://blog.fens.me/category/%E6%95%B0%E6%8D%AE%E5%BA%93/ 感谢! 在Ubuntu中安装Redis R利剑 ...
- 解决asp.net 以及MVC中上传文件大小限制的问题
﹤system.web﹥ ﹤httpruntime requestlengthdiskthreshold="256" maxrequestlength="2097151& ...
- android开发学习 ------- 【转】Gradle相关
一直在用AndroidStudio,但是对于其Gradle了解的很少. 推荐 http://www.jianshu.com/p/9df3c3b6067a 觉得说的很棒!
- C#控件置于底层或顶层
btn.BringToFront();//置于顶层 btn.SendToBack();//置于底层
- 文件及文件的操作-读、写、追加的t和b模式
1.什么是文件? 文件是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位. 文件的操作核心:读和写 对文件进行读写操作就是向操作系统发出指令,操作系统将用户或者应用程序对文件的读写操作转换为具体的 ...
- mysql中判断条件
if / case when 判断 SELECT CASE 1 WHEN 1 THEN "one" WHEN 2 THEN "two" ELSE "m ...
- Farseer.net轻量级ORM开源框架 V1.x 入门篇:存储过程实体类映射
导航 目 录:Farseer.net轻量级ORM开源框架 目录 上一篇:Farseer.net轻量级ORM开源框架 V1.x 入门篇:视图的数据操作 下一篇:Farseer.net轻量级ORM开源 ...
- ascii - 在八进制,十进制,十六进制中的 ASCII 字符集编码
描述 ASCII 是美国对于信息交换的标准代码,它是7位码,许多8位码(比如 ISO 8859-1, Linux 的默认字符集)容纳 ASCII 作为它们的下半部分.对应的国际 ASSII 是 ISO ...
- B4. Concurrent JVM 锁机制(synchronized)
[概述] JVM 通过 synchronized 关键字提供锁,用于在线程同步中保证线程安全. [synchronized 实现原理] synchronized 可以用于代码块或者方法中,产生同步代码 ...