NOIP 模拟 $50\; \rm 第负二题$
题解 \(by\;zj\varphi\)
首先考虑对于每一行二分答案 \(k\),考虑如何验证。
如果一个半径为 \(k\) 的菱形是在以当前行上的某一点为中心,且覆盖的格子全为 \(1\) 的一个最大菱形,那么 \(k+1\) 就是答案。
假设当前菱形的对称中心在第 \(i\) 行第 \(y\) 列,那么就会有
- 当 \(j<i\) 时,\(y\ge l_j+j+k-i\) 且 \(y\le r_j-j-k+i\),要求 \(y\) 有解,所以 \(\max_{j=i-k}^il_j+j+k-i\le \min_{j=i-k}^ir_j-j-k+i\)
- 当 \(j>i\) 时,\(y\ge l_j-j-k+i\) 且 \(y\le r_j+j-k-i\),要求 \(y\) 有解,所以 \(\max_{j=i-k}^il_j-j-k+i\le \min_{j=i-k}^ir_j+j-k-i\)
所以只需要维护 \(l_j-j,l_j-j,r_j+j,r_j-j\),可以用 \(rmq\) 预处理,复杂度 \(\mathcal{O\rm (nlogn)}\),会超时。
考虑如何优化,首先发现 \(|f_i-f_{i-1}|\le 1\),所以在下一回只用枚举三个答案。
其次,发现每一行所需要的判断范围单调不减,所以可以魔改一个单调队列。
所以,要维护四个单调队列,复杂度 \(\mathcal{O \rm(n)}\)。
Code
#include<bits/stdc++.h>
#define Re register
#define ri Re signed
#define pd(i) ++i
#define bq(i) --i
namespace IO{
char buf[1<<21],*p1=buf,*p2=buf;
#define gc() p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?(-1):*p1++
struct nanfeng_stream{
template<typename T>inline nanfeng_stream &operator>>(T &x) {
Re bool f=false;x=0;Re char ch=gc();
while(!isdigit(ch)) f|=ch=='-',ch=gc();
while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=gc();
return x=f?-x:x,*this;
}
}cin;
}
using IO::cin;
namespace nanfeng{
#define FI FILE *IN
#define FO FILE *OUT
template<typename T>inline T cmax(T x,T y) {return x>y?x:y;}
template<typename T>inline T cmin(T x,T y) {return x>y?y:x;}
using ull=unsigned long long;
using ll=long long;
static const int N=5e6+7,MOD=998244353;
int l[N],r[N],f[N],cnt,res,nm,n,L,X,Y;
ull A,B;
ll cm[N],ans;
auto random=[]() {
ull T=A,S=B;
A=S;
T^=T<<23;
T^=T>>17;
T^=S^(S>>26);
B=T;
return T+S;
};
auto mk=[]() {
for (ri i(1);i<=n;pd(i)) {
l[i]=random()%L+X;
r[i]=random()%L+Y;
if (l[i]>r[i]) std::swap(l[i],r[i]);
}
};
struct Dquel1{
int que[N],hd=1,tl=0;
std::function<bool(void)> exst=[=]() {return hd<=tl;};
std::function<int(int)> calc=[&](int x) {return l[que[x]]+que[x];};
std::function<void(int)> pop=[&](int lm) {while(hd<=tl&&que[hd]<lm) ++hd;};
std::function<void(int)> add=[&](int lm) {while(hd<=tl&&calc(tl)<=l[lm]+lm) --tl;que[++tl]=lm;};
}quel1;
struct Dquel2{
int que[N],hd=1,tl=0;
std::function<bool(void)> exst=[=]() {return hd<=tl;};
std::function<int(int)> calc=[&](int x) {return l[que[x]]-que[x];};
std::function<void(int)> pop=[&](int lm) {while(hd<=tl&&que[hd]<lm) ++hd;};
std::function<void(int)> add=[&](int lm) {while(hd<=tl&&calc(tl)<=l[lm]-lm) --tl;que[++tl]=lm;};
}quel2;
struct Dquer1{
int que[N],hd=1,tl=0;
std::function<bool(void)> exst=[=]() {return hd<=tl;};
std::function<int(int)> calc=[&](int x) {return r[que[x]]-que[x];};
std::function<void(int)> pop=[&](int lm) {while(hd<=tl&&que[hd]<lm) ++hd;};
std::function<void(int)> add=[&](int lm) {while(hd<=tl&&calc(tl)>=r[lm]-lm) --tl;que[++tl]=lm;};
}quer1;
struct Dquer2{
int que[N],hd=1,tl=0;
std::function<bool(void)> exst=[=]() {return hd<=tl;};
std::function<int(int)> calc=[&](int x) {return r[que[x]]+que[x];};
std::function<void(int)> pop=[&](int lm) {while(hd<=tl&&que[hd]<lm) ++hd;};
std::function<void(int)> add=[&](int lm) {while(hd<=tl&&calc(tl)>=r[lm]+lm) --tl;que[++tl]=lm;};
}quer2;
inline int main() {
// FI=freopen("nanfeng.in","r",stdin);
// FO=freopen("nanfeng.out","w",stdout);
cin >> n >> L >> X >> Y >> A >> B;
if (n==1) {puts("1");return 0;}
nm=n;
mk();
cm[0]=1;
for (ri i(1);i<=n;pd(i)) cm[i]=cm[i-1]*3%MOD;
f[1]=1;
quel1.add(1),quer1.add(1);
for (ri i(2);i<=n;pd(i)) {
f[i]=f[i-1]+1;
int tml1=0,tml2=0,tmr1=0,tmr2=0;
if (i+f[i-1]-1<=n) tml1=l[i+f[i-1]-1]-(i+f[i-1]-1),tmr1=r[i+f[i-1]-1]+(i+f[i-1]-1);
if (i+f[i]-1<=n) tml2=l[i+f[i]-1]-(i+f[i]-1),tmr2=r[i+f[i]-1]+(i+f[i]-1);
for (ri j(f[i]);j>=f[i-1]-1;bq(j)) {
if (i+j-1>n||i-j+1<1||i+j-1<i-j+1) continue;
int k=j-f[i-1];
auto check=[&]() {
bool jud;
if (k==1) {
int l2=cmax(tml1,tml2),r2=cmin(tmr1,tmr2);
if (quel2.exst()) {
l2=cmax(l2,quel2.calc(quel2.hd));
r2=cmin(r2,quer2.calc(quer2.hd));
}
if (quel1.exst()) {
l2=cmax(l2+(j-1)+i,quel1.calc(quel1.hd)+j-1-i);
r2=cmin(r2-(j-1)-i,quer1.calc(quer1.hd)-j+1+i);
}
jud=(l2<=r2);
if (jud) {
quel2.add(i+f[i-1]-1),quel2.add(i+f[i]-1),quel2.pop(i+1);
quer2.add(i+f[i-1]-1),quer2.add(i+f[i]-1),quer2.pop(i+1);
quel1.add(i),quer1.add(i);
}
} else if (!k) {
int l2=tml1,r2=tmr1;
quel1.pop(i-j+1),quer1.pop(i-j+1);
if (quel2.exst()) {
l2=cmax(l2,quel2.calc(quel2.hd));
r2=cmin(r2,quer2.calc(quer2.hd));
}
if (quel1.exst()) {
l2=cmax(l2+(j-1)+i,quel1.calc(quel1.hd)+j-1-i);
r2=cmin(r2-(j-1)-i,quer1.calc(quer1.hd)-j+1+i);
}
jud=(l2<=r2);
if (jud) {
quel2.add(i+f[i-1]-1),quel2.pop(i+1);
quer2.add(i+f[i-1]-1),quer2.pop(i+1);
quel1.add(i),quer1.add(i);
}
} else {
quel1.pop(i-j+1),quer1.pop(i-j+1);
int l2=quel2.calc(quel2.hd),r2=quer2.calc(quer2.hd);
if (quel1.exst()) {
l2=cmax(l2+(j-1)+i,quel1.calc(quel1.hd)+j-1-i);
r2=cmin(r2-(j-1)-i,quer1.calc(quer1.hd)-j+1+i);
}
jud=(l2<=r2);
quel2.pop(i+1),quer2.pop(i+1);
quel1.add(i),quer1.add(i);
}
return jud;
};
if (check()) {f[i]=j;break;}
}
}
for (ri i(1);i<=n;pd(i)) ans=(ans+cm[i-1]*f[i]%MOD)%MOD;
printf("%lld\n",ans);
return 0;
}
}
int main() {return nanfeng::main();}