二维平面网格中初始有
n
n
n个点,每一时刻某一位置存在点当且仅当上一时刻相邻四格中存在点,
Q
Q
Q次询问,求时刻
0
0
0到时刻
t
t
t平面上存在的点的总和。
n
≤
100
,
Q
≤
1
0
6
n\le100, Q\le10^6
n≤100,Q≤106
题解
当只有一个点时,手玩一下可以发现,每一时刻
t
t
t存在的点数为
(
t
+
1
)
2
(t+1)^2
(t+1)2。
当有多个点时,坐标
(
x
i
+
y
i
)
(x_i+y_i)
(xi+yi)奇偶性不同的点之间互不影响。
其中,有两个点且
(
x
i
+
y
i
)
(x_i+y_i)
(xi+yi)奇偶性相同时,两点扩展范围相交前互不影响,易得相交时间为
∣
x
i
−
x
j
∣
+
∣
y
i
−
y
j
∣
2
\frac{|x_i-x_j|+|y_i-y_j|}{2}
2∣xi−xj∣+∣yi−yj∣,即曼哈顿距离的一半,相交后它们重叠部分随时间增长为依次为
1
×
r
1\times r
1×r,
2
×
(
r
+
1
)
2\times (r+1)
2×(r+1),
3
×
(
r
+
2
)
3\times(r+2)
3×(r+2)……其中
r
=
m
i
n
(
∣
x
i
−
x
j
∣
,
∣
y
i
−
y
j
∣
)
r=min(|x_i-x_j|,|y_i-y_j|)
r=min(∣xi−xj∣,∣yi−yj∣)。
综上当
n
=
1
n=1
n=1或
2
2
2时,每一时刻
t
t
t的点数都是关于
t
t
t的二次多项式,从
0
0
0到
t
t
t求和后为关于
t
t
t的三次多项式,但
n
=
2
n=2
n=2相交前后的多项式系数不同。
那么,当
n
>
2
n>2
n>2时,若先求出两两相交时刻作为“关键时刻”,相邻两个关键时刻之间任一时刻
t
t
t的答案一定可以表示为同一个关于
t
t
t的三次多项式,只需要
4
4
4个位置的值,则可以把系数解出来或求答案时用拉格朗日插值求出来。
发现求每一时刻
t
t
t的总数即为求若干个边长为
t
+
1
t+1
t+1的正方形面积并,它们的左下角坐标为
(
x
i
+
y
i
2
,
x
i
−
y
i
2
)
(\frac{x_i+y_i}{2},\frac{x_i-y_i}{2})
(2xi+yi,2xi−yi),转换坐标后用线段树即可。
时间复杂度为
O
(
n
3
log
2
n
)
O(n^3\log_2n)
O(n3log2n),实现的不好可能需要一些优化:如把坐标离散化,而不使用动态开点;拉格朗日差值时预处理好分母之积的逆元。
代码
#include<cstdio>#include<cstring>#include<algorithm>usingnamespace std;#define ll long long#define md 998244353#define N 110struct node {int x, y, l, r, id;}a[2][N], b[2][N], h[N *2];struct qu {int x, l, r, c;}q[N *2];struct{int s, t, l, r;}f[N *16];int n, sum;int c[2], st[N * N], ti[2][N * N], si[2], fx[2][N * N][5];;
ll inv[2][N * N][5], he[N *2], le[N *4], ri[N *4];intdis(int o,int x,int y){returnabs(a[o][x].x - a[o][y].x)+abs(a[o][x].y - a[o][y].y);}intcmp(node x, node y){return x.x < y.x;}
ll ksm(ll x, ll y){if(!y)return1;
ll l =ksm(x, y /2);if(y %2)return l * l % md * x % md;return l * l % md;}voidins(int v,int l,int r,int x,int y,int c){if(x <= l && r <= y) f[v].t += c;else{int mid =(ll)((ll)l + r)/2;if(x <= mid){if(!f[v].l) f[v].l =++sum, f[sum].l = f[sum].r = f[sum].t =0;ins(f[v].l, l, mid, x, y, c);}if(y > mid){if(!f[v].r) f[v].r =++sum, f[sum].l = f[sum].r = f[sum].t =0;ins(f[v].r, mid +1, r, x, y, c);}}if(f[v].t) f[v].s = ri[r]- le[l]+1;else f[v].s = f[f[v].l].s + f[f[v].r].s;}
ll count(int o,int T){if(!c[o])return0;int tot =0;for(int i =1; i <= c[o]; i++){
h[++tot].x = b[o][i].y, h[tot].y =1, h[tot].id = i;
h[++tot].x = b[o][i].y + T, h[tot].y =2, h[tot].id = i;}sort(h +1, h + tot +1, cmp);int t0 =0;for(int i =1; i <= tot; i++){if(i ==1|| h[i].x > h[i -1].x) t0++;
he[t0]= h[i].x;if(h[i].y ==1) b[o][h[i].id].l = t0 *2-1;elseif(h[i].y ==2) b[o][h[i].id].r = t0 *2-1;}for(int i =1; i <= t0 *2-1; i++){if(i %2==0) ri[i]= he[i /2+1]-1, le[i]= he[i /2]+1;else le[i]= ri[i]= he[i /2+1];}int j =1, qs =0;for(int i =1; i <= c[o]; i++){while(b[o][j].x + T +1<= b[o][i].x && j <= c[o]){
q[++qs].x = b[o][j].x + T +1, q[qs].c =-1;
q[qs].l = b[o][j].l, q[qs].r = b[o][j].r;
j++;}
q[++qs].x = b[o][i].x, q[qs].c =1;
q[qs].l = b[o][i].l, q[qs].r = b[o][i].r;}while(j <= c[o]){
q[++qs].x = b[o][j].x + T +1, q[qs].c =-1;
q[qs].l = b[o][j].l, q[qs].r = b[o][j].r;
j++;}
ll ans =0;
sum =1, f[sum].l = f[sum].r = f[sum].s = f[sum].t =0;for(int i =1; i <= qs; i++){
ll t = f[1].s;if(i >1) ans =(ans + t *(q[i].x - q[i -1].x))% md;ins(1,1, t0 *2-1, q[i].l, q[i].r, q[i].c);}return ans;}
ll cs(int o,int T){if(!c[o])return0;int l =1, r = si[o], ts;while(l <= r){int mid =(l + r)/2;if(T >= ti[o][mid]) ts = mid, l = mid +1;else r = mid -1;}if(T - ti[o][ts]<4)return fx[o][ts][T - ti[o][ts]+1];
ll sum =0;for(int i =1; i <=4; i++){
ll s0 =1;for(int j =1; j <=4; j++)if(j != i) s0 = s0 *(T -(ti[o][ts]+ j -1))% md;
sum =(sum + s0 * inv[o][ts][i])% md;}return sum;}intread(){int s =0;char x =getchar();while(x <'0'|| x >'9') x =getchar();while(x >='0'&& x <='9') s = s *10+ x -48, x =getchar();return s;}voidwrite(int t){if(t ==0)puts("0");else{int bi[10]; bi[0]=0;while(t) bi[++bi[0]]= t %10, t /=10;while(bi[0])putchar(bi[bi[0]]+48), bi[0]--;puts("");}}intmain(){int Q, o, i, j, x, y;
n =read(), Q =read();for(i =1; i <= n; i++){
x =read(), y =read();
o =(x + y)%2;
c[o]++;
a[o][c[o]].x = x, a[o][c[o]].y = y;}for(o =0; o <1; o++){int mix =1e9, miy =1e9;for(i =1; i <= c[o]; i++){
b[o][i].x =(a[o][i].x + a[o][i].y)/2;
b[o][i].y =(a[o][i].x - a[o][i].y)/2;
mix =min(mix, b[o][i].x);
miy =min(miy, b[o][i].y);}int mx =0;for(i =1; i <= c[o]; i++) b[o][i].x -= mix -1, b[o][i].y -= miy -1, mx =max(b[o][i].x, mx), mx =max(b[o][i].y, mx);sort(b[o]+1, b[o]+ c[o]+1, cmp);}for(o =0; o <2; o++){
st[0]=0;for(i =1; i < c[o]; i++)for(j = i +1; j <= c[o]; j++) st[++st[0]]=dis(o, i, j)/2;sort(st +1, st + st[0]+1);
si[o]=1;
ti[o][1]=0;for(i =1; i <= st[0]; i++){if(i >1&& st[i]== st[i -1])continue;
ti[o][++si[o]]= st[i];}
ll la =0;for(i =1; i <= si[o]; i++){if(ti[o][i]==0) la =0;else la =cs(o, ti[o][i]-1);for(j = ti[o][i]; j < ti[o][i]+4&&(i == si[o]|| j < ti[o][i +1]); j++){
fx[o][i][++fx[o][i][0]]=(la +count(o, j))% md;
la = fx[o][i][fx[o][i][0]];}if(fx[o][i][0]==4){for(int ii =1; ii <=4; ii++){
inv[o][i][ii]=1;for(int jj =1; jj <=4; jj++)if(jj != ii) inv[o][i][ii]= inv[o][i][ii]*(ii - jj + md)% md;
inv[o][i][ii]= fx[o][i][ii]*ksm(inv[o][i][ii], md -2)% md;}}}}while(Q--){int t =read();write((cs(0, t)+cs(1, t))% md);}return0;}