题解:P7099 [yLOI2020] 灼
Cryn_Frog195 · · 题解
题意
给定
高斯消元做法
我们把坐标
直接用高斯消元是
打表与结论
这个时候套路已经结束,此时可以试图用
证:
由于
我们知道一阶差分为一次函数时原数组求积可得到二次函数,这就意味着
我们将
code
#include<bits/stdc++.h>
using namespace std;
int n,q,x[100009],pl[5000009],f[100009][4];//f[i][0] = g[i][i - 1],f[i][1] = g[i][i],f[i][2] = g[i][i + 1],f[i][2] = g[i][N + 1];
const int mod = 998244353;
int fp(int x,int y){
if(x == 0)
return 0;
if(y == 0)
return 1;
int t = fp(x,y >> 1);
t = 1ll * t * t % mod;
if(y & 1)
t = 1ll * t * x % mod;
return t;
}
int main(){
scanf("%*d %d %d",&n,&q);
for(int i = 1; i <= n; i ++){
scanf("%d",&x[i]);
}
sort(x + 1,x + n + 1);
if(x[n] <= 100000){//这里时70分部分分部分,赛场上用 if 将对应部分分分开处理有利于防掉大分。
for(int i = x[1]; i <= x[n]; i ++){
int o = lower_bound(x + 1,x + n + 1,i) - x;
if(x[o] == i){
f[i][1] = 1;
}
else{
f[i][0] = (mod + 1) >> 1,f[i][1] = mod - 1,f[i][2] = (mod + 1) >> 1,f[i][3] = mod - 1;
}
}
for(int i = x[1]; i < x[n]; i ++){
int d = fp(f[i][1],mod - 2);
f[i][1] = 1ll * d * f[i][1] % mod;
f[i][2] = 1ll * f[i][2] * d % mod;
f[i][3] = 1ll * f[i][3] * d % mod;
//printf("%d %d %d %d\n",f[i][0],f[i][1],f[i][2],f[i][3]);
f[i + 1][3] = (mod + f[i + 1][3] - 1ll * f[i + 1][0] * f[i][3] % mod) % mod;
f[i + 1][1] = (mod + f[i + 1][1] - 1ll * f[i + 1][0] * f[i][2] % mod) % mod;
f[i + 1][0] = 0;
}
for(int i = x[n]; i > x[1]; i --){
int d = fp(f[i][1],mod - 2);
f[i][1] = 1ll * d * f[i][1] % mod;
f[i][3] = 1ll * d * f[i][3] % mod;
f[i - 1][3] = (mod + f[i - 1][3] - 1ll * f[i][3] * f[i - 1][2] % mod) % mod;
f[i - 1][2] = 0;
}
int a = 0,b = 0,c = 0,d = 0x3f3f3f3f;
for(int i = 1; i <= q; i ++){
int y = 0;
scanf("%d",&y);
//printf(" %d\n",f[y][3]);
a = a ^ f[y][3];
b = b + (f[y][3] & 1);
c = max(c,f[y][3]);
d = min(d,f[y][3]);
}
printf("%d\n%d\n%d\n%d\n",a,b,c,d);
}
else{
int l = 1;
long long a = 0,b = 0,c = 0,d = 9e18;
for(int i = 1; i <= q; i ++){
int y;
long long ret;
scanf("%d",&y);
while(x[l + 1] <= y)
l++;
if(y == x[l])
ret = 0;
else{
int k = min(y - x[l],x[l + 1] - y);
int fl = x[l + 1] - x[l] - 1;
ret = 1ll * k * (fl - k + 1);
}
ret = ret % 998244353;
a = a ^ ret;
b += ret & 1;
c = max(c,ret);
d = min(d,ret);
}
printf("%lld\n%lld\n%lld\n%lld\n",a,b,c,d);
}
return 0;
}