@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. 一个页面多个bootstrip轮播以及一个页面多个swiper轮播 冲突问题

    Bootstript轮播冲突 解决方法: 使用不同的id <div id="myCarousel1" class="carousel slide"> ...

  2. laravel--laravel的重定向类Redirector

    laravel的重定向类Redirector 在laravel5中,重定向类可以直接通过redirect()方法直接获取,不需要声明,有几个常用的方法: redirect() -> to( “重 ...

  3. ajax请求数据以及处理

    html <div class="list-block media-list mp0 mbb" data-infos='infos' style="display: ...

  4. Codeforces 455B

    题目链接 B. A Lot of Games time limit per test 1 second memory limit per test 256 megabytes input standa ...

  5. zabbix自定义监控redis

    zabbix监控redis脚本 #!/bin/bash #此脚本用来获取redis-cli info信息 redis_cli="/usr/local/redis/bin/redis-cli& ...

  6. iFrame 父子窗口通讯

    今天就来说说 iFrame 的父子窗口通讯,关于 iFrame 这里就不陈述了,想要了解的盆友可以百度一下, 由于项目需要,前些天用到了个弹框框架 layer 弹出层,有很多弹出的方式,其中一种就是用 ...

  7. C# EventWaitHandle用法

    waithander就是用来阻塞当前线程的,然后通过set()方法放开 namespace waithandler { class Program { //static EventWaitHandle ...

  8. @Service ,@Controller,@Component注解

    首先,在applicationContext.xml文件中加一行: <context:component-scan base-package="com.hzhi.clas"/ ...

  9. 出现$(#form).validate is not a function的问题

    最近为项目写cms系统,在新增/编辑文章的页面,一些input诸如文章题目,作者等等需要验证是否已经填写,于是使用jquery.validate.js来做这个工作,自己写了个验证的validate.j ...

  10. Swift 和 Objective-C 混编后对ipa包大小的影响

    https://my.oschina.net/ilrrong/blog/800923 最近用Swift对以前写的一个应用进行重写,使用了Swift和Objective-C的混编,提交审核后发现比以前大 ...