@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. ES6学习笔记之字符串的扩展

    字符串的for of ES6 为字符串添加了遍历器接口,使得字符串可以被for...of循环遍历. const str='abcd'; for(let s of str){ console.log(s ...

  2. redis订阅自动退出

    1.打开报错, error_reporting(E_ALL);ini_set('display_errors', '1'); 2.没有报错,不是php最大执行时间问题,原因是socket超时3.有设置 ...

  3. 读书笔记--Head First Networking目录

    1.解决物理网络 2.规划网络布局 3.工具和故障排除 4.包分析 5.网络设备和流量 6.连接网络的路由器 7.路由协议 8.域名系统 9.监控和故障排除 10.无线网络 11.网络安全 12.网络 ...

  4. LintCode 链表倒数第n个节点

    找到单链表倒数第n个节点,保证链表中节点的最少数量为n. 样例 给出链表 3->2->1->5->null和n = 2,返回倒数第二个节点的值1. 分析:设两个指针 p1和p2 ...

  5. python 字符串的处理技巧--join

    >>> '+'.join('1234')'1+2+3+4'>>> '+'.join(a for a in '1234')'1+2+3+4'>>> ...

  6. python模拟浏览器文件上传,csrf放行

    服务器端视图函数 from django.shortcuts import render,HttpResponse from django.views.decorators.csrf import c ...

  7. vue 使用 element ui动态添加表单

    html部分 <div class="hello"> <el-form :model="dynamicValidateForm" ref=&q ...

  8. js点击复制文本

    // 动态创建 input 元素 var aux = document.createElement("input"); // 获得需要复制的内容 aux.setAttribute( ...

  9. mytop安装,使用mytop监控MySQL性能 (总结)

    mytop 是一个类似 Linux 下的 top 命令风格的 MySQL 监控工具,可以监控当前的连接用户和正在执行的命令. 1. 安装TermReadKey    下载地址:  wget  http ...

  10. WPF数据绑定详解

    元素绑定 数据绑定最简单的形式是,源对象是WPF元素而且源属性是依赖属性.依赖项属性具有内置的更改通知支持,当在源对象中改变依赖项属性的值时,会立即更新目标对相中的绑定属性. <!--Xaml程 ...