@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 秒后已经着火的面积,则最终答案为:

\[ans = (t + 1)*f(t) - \sum_{i=0}^{t}f(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的更多相关文章

  1. CF1086F Forest Fires

    CF1086F Forest Fires 有点意思的题目 直接统计每个格子的val是非常难办的.很难知道每秒新出来多少个格子 设$F[i]$表示,前i时刻覆盖的格子的数量 则,$ans=\sum_{i ...

  2. Note -「Lagrange 插值」学习笔记

    目录 问题引入 思考 Lagrange 插值法 插值过程 代码实现 实际应用 「洛谷 P4781」「模板」拉格朗日插值 「洛谷 P4463」calc 题意简述 数据规模 Solution Step 1 ...

  3. Python 爬取所有51VOA网站的Learn a words文本及mp3音频

    Python 爬取所有51VOA网站的Learn a words文本及mp3音频 #!/usr/bin/env python # -*- coding: utf-8 -*- #Python 爬取所有5 ...

  4. 数据可视化(一)-Matplotlib简易入门

    本节的内容来源:https://www.dataquest.io/mission/10/plotting-basics 本节的数据来源:https://archive.ics.uci.edu/ml/d ...

  5. 机器学习数据集,主数据集不能通过,人脸数据集介绍,从r包中获取数据集,中国河流数据集

    机器学习数据集,主数据集不能通过,人脸数据集介绍,从r包中获取数据集,中国河流数据集   选自Microsoft www.tz365.Cn 作者:Lee Scott 机器之心编译 参与:李亚洲.吴攀. ...

  6. 每日英语:A Buying Guide to Air-Pollution Masks

    Blue skies were finally visible in the capital on Thursday after the region suffered fromseven strai ...

  7. NCE2

    1.A private conversation Last week I went to the theatre. I had a very good seat. The play was very ...

  8. New Concept English Two 21 55

    $课文53  触电的蛇 544. At last firemen have put out a big forest fire in California. 消防队员们终于扑灭了加利福尼亚的一场森林大 ...

  9. L123

    My heart, the bird of the wilderness, has found its sky in your eyes. 我的心是旷野的鸟,在你的双眼中找到了天空.His main ...

随机推荐

  1. tr的display属性出现td的colspan无效问题

    http://www.aichengxu.com/other/9262680.htm 今天在做项目的时候发现用javascript控制 tr 的显示隐藏时,当把tr的显示由“display:none” ...

  2. Centos 设置时区

    参考网址: http://jingyan.baidu.com/article/636f38bb268a82d6b84610bd.html //打开设置 tzselect //选择 )Asia → )c ...

  3. Hackerrank--Divisibility of Power(Math)

    题目链接 You are given an array A of size N. You are asked to answer Q queries. Each query is of the for ...

  4. Spring线程安全的实现机制--ThreadLocal

    转载: http://blog.csdn.net/lufeng20/article/details/24314381

  5. “微信小程序” js部分注解

    1.小程序不提供获取dom的操作,而是让我们直接将事件绑定写入到组件内.区别在于bind不阻止冒泡,而catch阻止冒泡. <view id="tapTest" bindta ...

  6. GIT → 09:TortoiseGit 图形化工具

    GIT → 09:TortoiseGit 图形化工具

  7. 2019.7.27 NOIP模拟测试9 反思总结

    先来整理题目 T1题目大意:给出n个数字和一个质数作为模数,一个变量x初始值为1.进行m次操作,每次让x随机乘上n个数中的一个,问m次操作以后x的期望值. 答案一定可以用分数表示,输出分子乘分母逆元的 ...

  8. java-File类-字节流

    一 File 1.1 递归子目录 获取所有子目录中的内容 import java.io.File; public class GetAllFiles { /** * @param args */ pu ...

  9. golang之switch

  10. Javascript-正则表达式常用字符集及方法

    正则表达式修饰符(修饰符 可以在全局搜索中不区分大小写) i(ignoreCase)执行对大小写不敏感的匹配 g (global)     执行全局匹配(查找所有匹配而非在找到第一个匹配后停止) m( ...