@description@

在平面直角坐标系中,给定一个左下角为 (0, 0),右上角为 (Xp, Yp) 的矩形,并给定矩形内的 N 个点。

已知坐标系内有一个 K 边形,现将这个 K 边形平移。

问有多少种方案使最后 K 边形落入给定的矩形,定点在整数点上,且不包含 N 个点中的任意一个(与 K 边形的边、顶点重合也算包含)。

input

第一行包含三个整数 Xp, Yp, N (1 <= Xp, Yp <= 500, 0 <= N <= Xp*Yp )。

接下来 N 行每行包含两个整数 X, Y(0 < X < Xp, 0 < Y < Yp ),描述矩阵内的点。

接下来一行包含一个整数 K (3 <= K <= 10000)。

接下来 K 行每行包含两个整数 Xi, Yi(-10^9 <= Xi, Yi <= 10^9),描述了 K 边形的顶点。将这 K 个顶点顺次连接即可得到多边形。

output

输出一个整数,表示将 K 边形平移入矩形,且满足题目所给的限制的方案数。

sample input

5 5 3

1 4

1 3

2 2

3

4 7

6 3

7 6

sample output

3

@solution@

P.S:代码比文字也许更具说服力

看起来 K 边形顶点坐标都很大,但其实很容易发现如果要将 K 边形装进矩形,K 边形的大小肯定比矩形小。

所以我们可以将 K 边形的最小横坐标与最小纵坐标对应的点作为 K 边形的参照点,将这个参照点平移至原点,然后看 K 边形是否超出矩形的边界。如果超出直接输出方案数为 0。

考虑怎么求出 K 边形内部的所有点。先想想我们平时判断点是否在多边形内的方法:转角法、射线法。

某小蓝书强烈建议了转角法。然而你发现对于这道题,枚举每一个点然后用转角法判断是 O(m^2*K),其中 m 与 Xp, Yp 是同阶的。

但对于射线法就不一样了。因为所有点都是整数点,假如我们过 (x, y) 作一条垂直向下的射线,则我们完全可以利用 (x, y-1) 作出的射线进行转移,这样就可以不用重复计算,提高效率。

于是我们只需要从 y = 0 开始往右扫描,对于每一个 y 枚举 K 条边,看这 K 条边与当前的扫描线之间的关系,维护出射线法需要的东西。然后再从 x = 0 开始往上扫描,相当于将射线的端点一格一格往上移动。

这样时间复杂度就是 O(m^2 + mK) = O(mK) 的。

射线法在网上有很多很详细的教程,我这里仅提几点要点:

(1)对于点本身在边/顶点上的情况,特判。

(2)对于点引出的射线穿过顶点,考虑射线上的点仅属于射线的左边即可回避这个问题,判断相交时只需要看边的两个端点是否在射线的两边即可。

之后,我们可以枚举 K 边形的一个位置,再依次检查 N 个点是否合法。检查合法只需要看这个点与 K 边形的参照点的相对位置是否在我们之前算出来的所有在 K 边形内的点之中。

但是可以发现这个过程是 O(n^4) 的。

然后可能就是比较套路化的东西:我们将 K 边形内部的点全部记权值为 1,将 N 个点也全部记权值为 1。

决定了 K 边形参照点的位置过后,将对应位置的权值相乘然后相加,可以发现如果存在一个点在 K 边形内,则 1*1 = 1,最后结果就会非 0。

然后发现这是一个卷积的形式。

具体一点:我们记 A[i][j] 表示与 K 边形参照点相对坐标为 (i, j) 上的点是否在多边形内。

再记 B[i][j] 表示矩形中坐标 (i, j) 上是否有 N 个点中的一个。通过下面的式子计算:

\[C[x][y]=\sum_{i}\sum_{j}A[i][j]*B[x+i][y+j]
\]

如果 C[x][y] 为 0,说明将参照点平移至 (x, y) 是一种合法方案。

如果想要知道怎么计算这个式子,可以看参考这里(我懒得再写一遍了)。

@accepted code@

#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
const int MOD = 998244353;
const int G = 3;
const int MAXN = 1024;
const int MAXK = 10000;
const int INF = int(1E9);
struct vector{
int x, y;
vector(int _x=0, int _y=0):x(_x), y(_y){}
friend vector operator + (vector a, vector b) {return vector(a.x + b.x, a.y + b.y);}
friend vector operator - (vector a, vector b) {return vector(a.x - b.x, a.y - b.y);}
}pnt[MAXK + 5];
int A[MAXN + 5][MAXN + 5], B[MAXN + 5][MAXN + 5], C[MAXN + 5][MAXN + 5], D[MAXN + 5][MAXN + 5];
int pow_mod(int b, int p) {
int ret = 1;
while( p ) {
if( p & 1 ) ret = 1LL*ret*b%MOD;
b = 1LL*b*b%MOD;
p >>= 1;
}
return ret;
}
void ntt(int A[], int len, int type) {
for(int i=0,j=0;i<len;i++) {
if( i < j ) swap(A[i], A[j]);
for(int k=(len>>1);(j^=k)<k;k>>=1);
}
for(int s=2;s<=len;s<<=1) {
int t = (s>>1), u = (type == 1) ? pow_mod(G, (MOD-1)/s) : pow_mod(G, (MOD-1)-(MOD-1)/s);
for(int i=0;i<len;i+=s) {
for(int j=0,p=1;j<t;j++,p=1LL*p*u%MOD) {
int x = A[i+j], y = 1LL*p*A[i+j+t]%MOD;
A[i+j] = (x + y)%MOD, A[i+j+t] = (x + MOD - y)%MOD;
}
}
}
if( type == -1 ) {
int inv = pow_mod(len, MOD-2);
for(int i=0;i<len;i++)
A[i] = 1LL*A[i]*inv%MOD;
}
}
int main() {
int Xp, Yp, N, K;
scanf("%d%d%d", &Xp, &Yp, &N);
for(int i=1;i<=N;i++) {
int x, y; scanf("%d%d", &x, &y);
A[x][y] = 1;
}
scanf("%d", &K);
int mnx = INF, mny = INF, mxx = -INF, mxy = -INF;
for(int i=1;i<=K;i++) {
scanf("%d%d", &pnt[i].x, &pnt[i].y);
mnx = min(mnx, pnt[i].x), mny = min(mny, pnt[i].y);
}
vector d = vector(mnx, mny);
for(int i=1;i<=K;i++) {
pnt[i] = pnt[i] - d;
mxx = max(mxx, pnt[i].x), mxy = max(mxy, pnt[i].y);
}
pnt[K + 1] = pnt[1];
if( mxx > Xp || mxy > Yp ) {
puts("0");
return 0;
}
for(int x=0;x<=mxx;x++) {
for(int i=1;i<=K;i++) {
vector p1 = pnt[i], p2 = pnt[i + 1];
if( p1.x == p2.x ) {
if( p1.x == x ) {
for(int y=min(p1.y, p2.y);y<=p1.y||y<=p2.y;y++)
B[x][y] = 1;
}
}
else {
int y = ceil(p1.y + 1.0*(x - p1.x)*(p2.y - p1.y)/(p2.x - p1.x));
if( (p1.x <= x && x <= p2.x) || (p2.x <= x && x <= p1.x) )
if( (p2.x - p1.x)*(y - p1.y) == (x - p1.x)*(p2.y - p1.y) )
B[x][y] = 1;
if( (p1.x <= x && x < p2.x) || (p2.x <= x && x < p1.x) )
C[x][y]++;
}
}
int d = 0;
for(int y=0;y<=mxy;y++) {
d += C[x][y];
if( d & 1 ) B[x][y] = 1;
}
}
for(int i=0;i<=Xp;i++)
for(int j=0;j<=Yp;j++)
if( j < Yp - j ) swap(A[i][j], A[i][Yp - j]);
for(int j=0;j<=Yp;j++)
for(int i=0;i<=Xp;i++)
if( i < Xp - i ) swap(A[i][j], A[Xp - i][j]);
int len; for(len= 1; len <= 2*Xp || len <= 2*Yp; len <<= 1);
for(int i=0;i<len;i++)
ntt(A[i], len, 1), ntt(B[i], len, 1);
for(int i=0;i<len;i++)
for(int j=0;j<len;j++)
if( i < j ) swap(A[i][j], A[j][i]), swap(B[i][j], B[j][i]);
for(int i=0;i<len;i++)
ntt(A[i], len, 1), ntt(B[i], len, 1);
for(int p=0;p<len;p++)
for(int q=0;q<len;q++)
D[q][p] = (D[q][p] + 1LL*A[q][p]*B[q][p]%MOD)%MOD;
for(int i=0;i<len;i++)
ntt(D[i], len, -1);
for(int i=0;i<len;i++)
for(int j=0;j<len;j++)
if( i < j ) swap(D[i][j], D[j][i]);
for(int i=0;i<len;i++)
ntt(D[i], len, -1);
for(int i=0;i<=Xp;i++)
for(int j=0;j<=Yp;j++)
if( j < Yp - j ) swap(D[i][j], D[i][Yp - j]);
for(int j=0;j<=Yp;j++)
for(int i=0;i<=Xp;i++)
if( i < Xp - i ) swap(D[i][j], D[Xp - i][j]);
int ans = 0;
for(int p=0;p<=Xp-mxx;p++)
for(int q=0;q<=Yp-mxy;q++)
if( !D[p][q] ) ans++;
printf("%d\n", ans);
}

@details@

比较套路化的一道题吧。。。思路上相较而言没有什么新奇的地方。。。

不过对于好久没有复习卷积和计算几何的我倒是可以练一练复习一下。

所以我也不知道为什么这样一道题我可以废话这么多。。。

@COCI 2016/2017 Round 3@ Meksikanac的更多相关文章

  1. [SinGuLaRiTy] COCI 2016~2017 #5

    [SinGuLaRiTy-1012] Copyright (c) SinGuLaRiTy 2017. All Rights Reserved. 最近神犇喜欢考COCI...... 测试题目 对于所有的 ...

  2. 【转】2016/2017 Web 开发者路线图

    链接:知乎 [点击查看大图] 原图来自LearnCodeAcademy最火的视频,learncode是YouTube上最火的Web开发教学频道,介绍包括HTML/CSS/JavaScript/Subl ...

  3. Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 菜鸡只会ABC!

    Codeforces Round #405 (rated, Div. 2, based on VK Cup 2017 Round 1) 全场题解 菜鸡只会A+B+C,呈上题解: A. Bear and ...

  4. COCI 2015、2016 1st round 题解(官方)

    官方题解: 官方代码: Code-KARTE: #include <cstdio> #include <iostream> #include <cstring> u ...

  5. Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3)(A.B.C,3道暴力题,C可二分求解)

    A. Is it rated? time limit per test:2 seconds memory limit per test:256 megabytes input:standard inp ...

  6. 关于ECMAScript 2016, 2017, 和2018中新增功能(摘抄)

    ECMAScript 2016 1. Array.prototype.includes includes是数组上的简单实例方法,并有助于轻松查找某个项是否在Array中(包括NaN不像indexOf) ...

  7. SQL Server 2012/2016/2017 新增函数

    /************************************************************** SQL Server 2012 新增的函数 ************** ...

  8. Codeforces Round #412 (rated, Div. 2, base on VK Cup 2017 Round 3) A B C D 水 模拟 二分 贪心

    A. Is it rated? time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  9. ECMAScript 2016,2017 和 2018 中所有新功能的示例

    很难追踪 JavaScript(ECMAScript)中的新功能. 想找到有用的代码示例更加困难. 因此,在本文中,我将介绍 TC39 已完成 ES2016,ES2017 和 ES2018(最终草案) ...

随机推荐

  1. Flask中的session机制

    cookie和sessioncookie:网站中,http请求是无状态的,第一次和服务器连接后并且登陆成功后,第二次请求服务器依然不能知道当前请求是哪个用户.cookie的出现就是解决了改问题,第一次 ...

  2. config.js配置页面中的样式和图片路径

    这个文章用在什么地方,我先说一下,上周啊,我接到一个任务.因为公司业务要对接不同的银行,例如在工行下颜色是红色的,在其他银行下默认为蓝色,所以在页面一致的情况下,保证页面中的按钮和ICON是可以配置的 ...

  3. Faster RCNN算法训练代码解析(1)

    这周看完faster-rcnn后,应该对其源码进行一个解析,以便后面的使用. 那首先直接先主函数出发py-faster-rcnn/tools/train_faster_rcnn_alt_opt.py ...

  4. IntelliJ IDEA 下的svn配置及使用的非常详细的图文总结(转)

    IntelliJ IDEA使用教程 (总目录篇) 首先,使用的时候,自己得先在电脑上安装个小乌龟.也就是svn啦. 第一步安装小乌龟. 如下: 具体安装好像没什么具体要求,一路next,就好. 如上图 ...

  5. DirectX11笔记(一)--配置DirectX工程

    原文:DirectX11笔记(一)--配置DirectX工程 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u010333737/article/d ...

  6. TyvjP1266 费解的开关

    P1266 费解的开关 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述     你玩过“拉灯”游戏吗?25盏灯排成一个5x5的方形.每一个灯都有一个开关,游戏 ...

  7. typeof与js数据类型

    js有6种数据类型有null.undefied.string.number.boolean.object. 然而我之前的[误区]: typeof的返回值和JS的数据类型是一样的.但是并不是(⊙o⊙)哦 ...

  8. AlertDialog提示对话框练习

    闲来无事,就练习了下AlertDialog对话框. 首先写了三个button,分别打开一般对话框,单选列表对话框和复选对话框. xml代码 <LinearLayout xmlns:android ...

  9. pycharm 2017 序列号失效问题解决(2016-2017版本都有效)

    pycharm 序列号失效问题解决   this license BIG3CLIK6F has been cancelled  具体如下: 对,没错,这个激活码本来可以使用到2018年的,但是,忽然间 ...

  10. Directx11教程40 纹理映射(10)

    原文:Directx11教程40 纹理映射(10)      本章尝试使用纹理行列式,或者说纹理数组,在ps中,使用2个纹理,最终的像素颜色,是光照颜色*纹理1采样颜色*纹理2采样颜色,主要是想达到如 ...