【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 ...
随机推荐
- 使用 Suricata 进行入侵监控(一个简单小例子访问百度)
前期博客 基于CentOS6.5下Suricata(一款高性能的网络IDS.IPS和网络安全监控引擎)的搭建(图文详解)(博主推荐) 1.自己编写一条规则,规则书写参考snort规则(suricata ...
- 多功能Markdown编辑器MarkdownPad 2的下载、安装和初步使用步骤(图文详解)(博主推荐)
不多说,直接上干货! MarkdownPad 是什么? 一.MarkdownPad 2的下载 http://markdownpad.com/download/markdownpad2-setup. ...
- 关于 user agent ua
1.ua介绍: ua查询参考网址:http://www.atool.org/useragent.php(也可以自己制作html查询) js 属性:navigator.userAgent 使用方法:将网 ...
- mac系统 usr/ 目录下无法新建文件夹???
这个问题是在操作mongodb的时候遇到的,很苦恼.目前已经解决,将解决方法分享给各位遇到同样问题的你们. 1.重启电脑,开始关机就立马按住command+R,进入macOS恢复功能界面,进入的时间可 ...
- 使用Kotlin,抛弃findViewById
有没有觉得Android的findViewById挺烦人的.使用Kotlin可以让你彻底抛弃这个烦恼 步骤1.在build.gradle(Module:app)中添加如下一句话 这个在老一点版本的An ...
- Android SDK镜像更新网速慢的解决问题
通过更换代理解决 Android SDK 在线更新镜像服务器资源:大连东软信息学院镜像服务器地址:http://mirrors.neusoft.edu.cn 端口:80北京化工大学镜像服务器地址:IP ...
- OpenFlow_tutorial_4_Create_a_Learning_Switch
一.环境搭建: 教程里提供的VM image需要梯子才能下载,好不容易下载下来,发现镜像很难用,各种安装问题,搞了好几天也解决不了.后来就自己搭环境,主要是安装Ryu. 1.首先下载相应的python ...
- CREATE LANGUAGE - 定义一种新的过程语言
SYNOPSIS CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE name HANDLER call_handler [ VALIDATOR valfunctio ...
- 实训day01 python基础
一.编程语言 编程语言:可以被计算机所识别的表达方式. 编程:程序员通过编程语言将自己的想法编写出来,产生的结果就是包含字符的文件. 其中,只有程序在运行时,其中的字符才有特定的语法意义. 二.计算机 ...
- iphone X 的适配
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...