@codeforces - 1086F@ Forest Fires
@description@
一个无穷大的方格图,每个方格内都种了棵树。
一开始点燃了 n 棵树。之后的每一秒内,火都会从一个格子蔓延到共边或者共顶点的方格。t 秒后,火停止蔓延。
记 val(x, y) 为方格 (x, y) 被点燃的时间,如果未被点燃,则 val(x, y) = 0。
求所有格子的 val 之和。模 998244353。
Input
第一行两个整数 n 和 t (1≤n≤50, 0≤t≤10^8)。
接下来 n 行每行两个整数 x 与 y (−10^8≤x, y≤10^8),表示初始着火的坐标。
保证所有坐标互不相同。
Output
输出一个整数表示 val 之和模 998244353。
Examples
Input
1 2
10 11
Output
40
Input
4 1
2 2
1 3
0 2
2 4
Output
18
Input
3 0
0 0
-2 1
1 1
Output
0
Note
以下是三个样例分别对应的图:

@solution@
我们先稍微转换一下问题。记 f(i) 表示 i 秒后已经着火的面积,则最终答案为:
\]
当然这个转换并不是必需的,只是更方便一些。
若给定 i,求 f(i) 可以一波扫描线搞定。暴力扫描线 O(n^2),线段树优化可以做到 O(nlogn)(但没必要啊喂)。
假如只有一个起火点,则 f(t) 呈二次函数增长。这个显然。
假如有两个起火点,当两个区域不相交时显然 f(t) 呈二次函数增长;相交时,总面积 = 面积之和 - 相交面积。
矩形的交仍是矩形,故相当于是二次函数 - 二次函数,还是个二次的函数。
假如有 n 个起火点,则根据容斥原理并仿照上面的证明,也可以得证在相交情况不变的前提下,f(t) 呈二次函数增长。
因为 a 与 b 相交,b 与 c 相交,c 与 a 相交时,可以得到 a, b 与 c 存在共同的相交部分(因为它们都是矩形)。
也就是说,矩阵两两相交的 O(n^2) 个时刻,将 f(t) 划分成 O(n^2) 个分段函数,每个函数都是个二次函数。
既然 f(t) 是二次函数,那么 \(\sum f(t)\) 自然就是一个三次函数。插值插一下就插出来啦。
@accepted code@
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 50;
const int MOD = 998244353;
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;
}
inline int add(int a, int b) {return (a + b)%MOD;}
inline int mul(int a, int b) {return 1LL*a*b%MOD;}
inline int sub(int a, int b) {return add(a, (MOD - b)%MOD);}
inline int inv(int x) {return pow_mod(x, MOD - 2);}
vector<int>v1[2*MAXN + 5], v2[2*MAXN + 5];
int x[MAXN + 5], y[MAXN + 5], n;
int dx[2*MAXN + 5], dy[2*MAXN + 5], xcnt, ycnt;
int tag[2*MAXN + 5];
int func(int t) {
xcnt = ycnt = 0;
for(int i=1;i<=n;i++) {
dx[++xcnt] = x[i] + t + 1, dx[++xcnt] = x[i] - t;
dy[++ycnt] = y[i] + t + 1, dy[++ycnt] = y[i] - t;
}
sort(dx + 1, dx + xcnt + 1), xcnt = unique(dx + 1, dx + xcnt + 1) - dx - 1;
sort(dy + 1, dy + ycnt + 1), ycnt = unique(dy + 1, dy + ycnt + 1) - dy - 1;
for(int i=1;i<=xcnt;i++) v1[i].clear(), v2[i].clear();
for(int i=1;i<=n;i++) {
int l = lower_bound(dx + 1, dx + xcnt + 1, x[i] - t) - dx;
int r = lower_bound(dx + 1, dx + xcnt + 1, x[i] + t + 1) - dx;
v1[l].push_back(i), v2[r].push_back(i);
}
int ans = 0;
for(int i=1;i<=xcnt;i++) {
int tmp = 0;
for(int j=1;j<=ycnt;j++) {
if( tmp ) ans = add(ans, mul(dy[j] - dy[j-1], dx[i] - dx[i-1]));
tmp += tag[j];
}
for(int j=0;j<v1[i].size();j++) {
int p = v1[i][j];
int u = lower_bound(dy + 1, dy + ycnt + 1, y[p] - t) - dy;
int d = lower_bound(dy + 1, dy + ycnt + 1, y[p] + t + 1) - dy;
tag[u]++, tag[d]--;
}
for(int j=0;j<v2[i].size();j++) {
int p = v2[i][j];
int u = lower_bound(dy + 1, dy + ycnt + 1, y[p] - t) - dy;
int d = lower_bound(dy + 1, dy + ycnt + 1, y[p] + t + 1) - dy;
tag[u]--, tag[d]++;
}
}
return ans;
}
struct point{
int x, y;
point(int _x=0, int _y=0):x(_x), y(_y) {}
};
int func3(point *p, int x) {
int ret = 0;
for(int i=0;i<4;i++) {
int del = 1;
for(int j=0;j<4;j++)
if( i != j ) del = mul(del, mul(sub(x, p[j].x), inv(sub(p[i].x, p[j].x))));
ret = add(ret, mul(del, p[i].y));
}
return ret;
}
int func2(int l, int r) {
if( r - l + 1 <= 3 ) {
int ret = 0;
for(int i=l;i<=r;i++) ret = add(ret, func(i));
return ret;
}
point p[4] = {point(l, func(l))};
for(int i=1;i<4;i++)
p[i] = point(l + i, add(p[i - 1].y, func(l + i)));
return (sub(func3(p, r), func3(p, l - 1)) + MOD)%MOD;
}
int a[MAXN*MAXN + 5], cnt;
int main() {
int t; scanf("%d%d", &n, &t);
for(int i=1;i<=n;i++)
scanf("%d%d", &x[i], &y[i]);
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++) {
int p = max((abs(x[i] - x[j]) - 1) >> 1, (abs(y[i] - y[j]) - 1) >> 1);
if( p <= t ) a[++cnt] = p;
}
a[++cnt] = t;
sort(a + 1, a + cnt + 1), cnt = unique(a + 1, a + cnt + 1) - a - 1;
int ans = mul(t + 1, func(t)), lst = 0;
for(int i=1;i<=cnt;i++)
ans = sub(ans, func2(lst, a[i])), lst = a[i] + 1;
printf("%d\n", ans);
}
@details@
插值点不够就直接暴力算。
一开始看错题。。。还以为是只能共边的格子传递。。。
@codeforces - 1086F@ Forest Fires的更多相关文章
- CF1086F Forest Fires
CF1086F Forest Fires 有点意思的题目 直接统计每个格子的val是非常难办的.很难知道每秒新出来多少个格子 设$F[i]$表示,前i时刻覆盖的格子的数量 则,$ans=\sum_{i ...
- Note -「Lagrange 插值」学习笔记
目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...
- Python 爬取所有51VOA网站的Learn a words文本及mp3音频
Python 爬取所有51VOA网站的Learn a words文本及mp3音频 #!/usr/bin/env python # -*- coding: utf-8 -*- #Python 爬取所有5 ...
- 数据可视化(一)-Matplotlib简易入门
本节的内容来源:https://www.dataquest.io/mission/10/plotting-basics 本节的数据来源:https://archive.ics.uci.edu/ml/d ...
- 机器学习数据集,主数据集不能通过,人脸数据集介绍,从r包中获取数据集,中国河流数据集
机器学习数据集,主数据集不能通过,人脸数据集介绍,从r包中获取数据集,中国河流数据集 选自Microsoft www.tz365.Cn 作者:Lee Scott 机器之心编译 参与:李亚洲.吴攀. ...
- 每日英语:A Buying Guide to Air-Pollution Masks
Blue skies were finally visible in the capital on Thursday after the region suffered fromseven strai ...
- NCE2
1.A private conversation Last week I went to the theatre. I had a very good seat. The play was very ...
- New Concept English Two 21 55
$课文53 触电的蛇 544. At last firemen have put out a big forest fire in California. 消防队员们终于扑灭了加利福尼亚的一场森林大 ...
- L123
My heart, the bird of the wilderness, has found its sky in your eyes. 我的心是旷野的鸟,在你的双眼中找到了天空.His main ...
随机推荐
- freopen() 函数的使用
当我们求解acm题目时,通常在设计好算法和程序后,要在调试环境(例如VC等)中运行程序,输入测试数据,当能得到正确运行结果后,才将程序提交到oj中.但由于调试往往不能一次成功,每次运行时,都要重新输入 ...
- python统计一个文本中重复行数的方法
python统计一个文本中重复行数的方法 这篇文章主要介绍了python统计一个文本中重复行数的方法,涉及针对Python中dict对象的使用及相关本文的操作,具有一定的借鉴价值,需要的朋友可以参考下 ...
- jnhs中国省市县区mysql数据表不带gps坐标
1.查省 SELECT * FROM china WHERE china.Pid=0 2.查市 SELECT * FROM chinaWHERE china.Pid=330000 3.查区 SELEC ...
- Git同账号多平台配置
最近工作中使用到了Git,虽然以前学习过,但是已经忘的差不多了,遂将本次配置过程整理成笔记以备忘 生成公钥 ssh-keygen -t rsa -C "gana10007@163.com&q ...
- find()和find_all()的具体使用
在我们学会了BeautifulSoup库的用法后,我们就可以使用这个库对HTML进行解析,从网页中提取我们需要的内容. 在BeautifulSoup 文档里,find().find_all()两者的定 ...
- python基础--闭包and装饰器
闭包函数:函数内部定义的函数:引用了外部变量但非全局变量 装饰器:有了闭包的概念再去理解装饰器就会相对容易一些.python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加 ...
- java-面向对象-封装-this-构造函数
概要图 一 构造函数 需求:为了描述事物更准确,发现事物对应的很多对象一创建时, 就有了,一些初始化的数据.在类中该如何完成的. 通过Java中的另一个小技术完成:就是构造函数.对象本身就是构造出 ...
- golang之字符串
字符串中的每一个元素叫做“字符”.在遍历或者单个获取字符串元素时可以获得字符.严格来说,这并不是 Go语言的一个类型,字符只是整数的特殊用例. (1)最后要注意,字符串值是不可变的.也就是说,我们一旦 ...
- HR招聘_(七)_招聘方法论(面试环节·动机判断)
候选人选择一般会看硬性技能,软性技能,动机意愿三个方面的匹配程度,硬性技能主要指纵向的业务能力,部门面试官也会着重看这方面,软性技能包括沟通,情商,气质等.动机意愿非常重要,再优秀的如果没有意愿,动机 ...
- web前端学习(三)css学习笔记部分(1)-- css入门基础知识+基本样式
1.介绍及语法 1.1CSS概述: CSS指层叠样式表 CSS样式表极大地提高了工作效率 如果值大于一个单词,需要加上引号(意思是值只有一个的时候可以不加引号) 1.2CSS高级语法 1.选择器分组 ...