题解 第负二题

传送门

先玩个梗:

额……数据是经过我们精心构造的

别接梗,小心禁三

先给个结论吧:\(n^2\) 能AC,所以你也许不用往下看了
upd:战神加强了数据,揉揉可爱战神!

首先有一个 \(O(n^2)\) 的做法:
把最外层的点扔进一个队列,每次扩展与这个点相邻的且未扩展过的点
每个点入队一次,所以是 \(O(\text{点数})\) 的,但时空平衡后基本是 \(n^2\) 的,而且不是能过的那种 \(n^2\)

至于正解:
先转化下题意,第 \(i\) 行的一个点 \(y\) 在时刻 \(k+1\) 能活着的前提是能找到一个以 \(y\) 为中心,\(k\)\(\frac{\text{对角线长}}{2}\) 的菱形
也即 \(y-(k-(i-j)) \geqslant l_j\)\(y+(k-(i-j)) \leqslant r_j\)\(j \in [i-k, i]\) 恒成立,下面同理
整理一下,有 \(y \geqslant max(l_j-j)+i+k\)\(y \leqslant min(r_j+j)-i-k\)
那就卡出了一个 \(y\) 的范围,判断范围是否为空就可以
发现是静态区间在线求最值,可以RMQ \(O(1)\)
那现在对于第 \(I\) 行,我们可以 \(O(1)\) check一个时刻是否合法了
那就可以二分了,复杂度 \(O(nlogn)\),实测稍劣于 \(n^2\)(雾

考虑优化,发现瓶颈在于二分和RMQ的预处理
发现两行被消完的时间差不会大于1,即 \(| f_i-f_{i-1} | \leqslant 1\)
\(f_i\) 只有三种取值,可以省掉二分的过程
此时已经可以拿到90pts,但时空双爆,且全爆在RMQ上了
所以考虑优化掉RMQ
刚才说了 \(f_i\) 变化范围只有1
考虑 \(i\) 对应的菱形和 \(i-1\) 对应的菱形间的关系
手模下三种情况会发现菱形的上下边界都单调,可以上单调队列
然后就没有了,注意check三种取值的时候如果在check时就向队列中添加元素,可能需要回滚
可以考虑每次对「队列中的max」与「想加入的元素」取max以判断是否合法
\(f_i\) 的取值已经确定之后再对应向单调队列中添加元素
就可以避免回滚
最终复杂度 \(O(n)\)
特别注意用快速幂会多个log

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 5000010
#define ll long long
#define ull unsigned long long
typedef unsigned long long u64;
#define reg register int
#define fir first
#define sec second
#define make make_pair
//#define int long long 

int n, L, X, Y;
ull A, B;
int l[N], r[N], f[N];
bool mp[1000][1000];
const int dlt[][2]={{-1,0},{1,0},{0,-1},{0,1}};
const ll mod=998244353;
inline void md(ll& a, ll b) {a+=b; a=a>=mod?a-mod:a;}
ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod, b>>=1) if (b&1) ans=ans*a%mod; return ans;}
void put() {
	for (int i=1; i<=n; ++i) 
		for (int j=l[i]; j<=r[i]; ++j) mp[i][j]=1;
	for (int i=1; i<=n; ++i) {cout<<setw(2)<<i<<": "; for (int j=1; j<=Y+L; ++j) cout<<mp[i][j]<<' '; cout<<endl;}
}

u64 xorshift128p(u64 &A, u64 &B) { 
    u64 T = A, S = B; 
    A = S; 
    T ^= T << 23; 
    T ^= T >> 17; 
    T ^= S ^ (S >> 26); 
    B = T; 
    return T + S;
} 
   
void gen(int n, int L, int X, int Y, u64 A, u64 B, int l[], int r[]) { 
    for (reg i = 1; i <= n; i ++) { 
        l[i] = xorshift128p(A, B) % L + X; 
        r[i] = xorshift128p(A, B) % L + Y; 
        if (l[i] > r[i]) swap(l[i], r[i]); 
    } 
}

namespace force{
	int cnt[150], top;
	bool mp[150][150];
	pair<int, int> sta[N];
	queue< pair<int, int> > q1, q2;
	void solve() {
		for (int i=1; i<=n; ++i) {
			cnt[i]=r[i]-l[i]+1;
			for (int j=l[i]; j<=r[i]; ++j) mp[i][j]=1, q1.push(make(i, j));
		}
		for (int now=1; q1.size(); ++now) {
			pair<int, int> u;
			while (q1.size()) {
				u=q1.front(); q1.pop();
				for (int i=0,x,y; i<4; ++i) {
					x=u.fir+dlt[i][0], y=u.sec+dlt[i][1];
					if (x<1||x>n||y<1||y>n||!mp[x][y]) {sta[++top]=u; goto jump;}
				}
				q2.push(u);
				jump: ;
			}
			while (top) {
				mp[sta[top].fir][sta[top].sec]=0;
				if (--cnt[sta[top].fir]==0) f[sta[top].fir]=now;
				--top;
			}
			swap(q1, q2);
		}
		//cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
		ll ans=0;
		for (int i=1; i<=n; ++i) md(ans, qpow(3ll, i-1)*f[i]%mod);
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task1{
	int cnt[2500], top;
	bool mp[2500][2500], vis[2500][2500];
	pair<int, int> sta[N];
	queue< pair<int, int> > q1, q2, qs;
	void solve() {
		for (int i=1; i<=n; ++i) {
			cnt[i]=r[i]-l[i]+1;
			for (int j=l[i]; j<=r[i]; ++j) mp[i][j]=1, qs.push(make(i, j));
		}
		pair<int, int> u;
		while (qs.size()) {
			u=qs.front(); qs.pop();
			for (int i=0,x,y; i<4; ++i) {
				x=u.fir+dlt[i][0], y=u.sec+dlt[i][1];
				if (x<1||x>n||y<1||y>n||!mp[x][y]) {q1.push(u); vis[u.fir][u.sec]=1; break;}
			}
		}
		for (int now=1; q1.size(); ++now) {
			pair<int, int> u;
			while (q1.size()) {
				u=q1.front(); q1.pop();
				for (int i=0,x,y; i<4; ++i) {
					x=u.fir+dlt[i][0], y=u.sec+dlt[i][1];
					if (x>=1&&x<=n&&y>=1&&y<=n&&mp[x][y]&&!vis[x][y]) q2.push(make(x, y)), vis[x][y]=1;
				}
				mp[u.fir][u.sec]=0;
				if (--cnt[u.fir]==0) f[u.fir]=now;
			}
			swap(q1, q2);
		}
		//cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
		ll ans=0;
		for (int i=1; i<=n; ++i) md(ans, qpow(3ll, i-1)*f[i]%mod);
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task2{
	int ls1[23][N], ls2[23][N], rs1[23][N], rs2[23][N], lg[N];
	ll ans;
	inline int qmax(int st[][N], int l, int r) {
		int t=lg[r-l+1]-1;
		return max(st[t][l], st[t][r-(1<<t)+1]);
	}
	inline int qmin(int st[][N] , int l, int r) {
		int t=lg[r-l+1]-1;
		return min(st[t][l], st[t][r-(1<<t)+1]);
	}
	bool check(int i, int k) {
		//cout<<"check: "<<i<<' '<<k<<endl;
		--k;
		//if (i<k || i+k>n) return 0;
		//cout<<"qmax: "<<qmax(ls1, i, i+k)<<' '<<qmax(ls2, i-k, i)<<endl;
		int l=max(qmax(ls1, i, i+k)+i+k, qmax(ls2, i-k, i)-i+k);
		int r=min(qmin(rs1, i, i+k)-i-k, qmin(rs2, i-k, i)+i-k);
		//cout<<"lr: "<<l<<' '<<r<<' '<<(l<=r)<<endl;
		return l<=r;
	}
	void solve() {
		//cout<<double(sizeof(ls1)*4+sizeof(lg)*2)/1024/1024<<endl;
		for (reg i=1; i<=n; ++i) lg[i]=lg[i-1]+(1<<lg[i-1]==i);
		for (reg i=1; i<=n; ++i) ls1[0][i]=l[i]-i, ls2[0][i]=l[i]+i, rs1[0][i]=r[i]+i, rs2[0][i]=r[i]-i;
		int lim=lg[n]-1;
		for (reg i=1; i<=lim; ++i) {
			for (reg j=1; j<=n-(1<<i)+1; ++j) {
				ls1[i][j]=max(ls1[i-1][j], ls1[i-1][j+(1<<(i-1))]);
				ls2[i][j]=max(ls2[i-1][j], ls2[i-1][j+(1<<(i-1))]);
				rs1[i][j]=min(rs1[i-1][j], rs1[i-1][j+(1<<(i-1))]);
				rs2[i][j]=min(rs2[i-1][j], rs2[i-1][j+(1<<(i-1))]);
			}
		}
		for (reg i=1; i<=n; ++i) {
			if (check(i, f[i-1]+1)) f[i]=f[i-1]+1;
			else if (check(i, f[i-1])) f[i]=f[i-1];
			else f[i]=f[i-1]-1;
			md(ans, qpow(3ll, i-1)*f[i]%mod);
		}
		printf("%lld\n", ans);
		exit(0);
	}
}

namespace task{
	ll ans;
	int up=1, down=1;
	ll pow2[N];
	struct que1{
		int l=1, r=0;
		struct node{int val, pos; inline void build(int v_, int p_) {val=v_; pos=p_;}}q[N];
		inline int query() {return l<=r?q[l].val:-INF;}
		inline int size() {return r-l+1;}
		inline void upd(int deline) {
			while (l<=r && q[l].pos<deline) ++l;
		}
		inline void add(int v, int p) {
			while (l<=r && q[r].val<=v) --r;
			q[++r].build(v, p);
		}
	}l1, l2;
	struct que2{
		int l=1, r=0;
		struct node{int val, pos; inline void build(int v_, int p_) {val=v_; pos=p_;}}q[N];
		inline int query() {return l<=r?q[l].val:INF;}
		inline int size() {return r-l+1;}
		inline void upd(int deline) {
			while (l<=r && q[l].pos<deline) ++l;
		}
		inline void add(int v, int p) {
			while (l<=r && q[r].val>=v) --r;
			q[++r].build(v, p);
		}
	}r1, r2;
	
	void solve() {
		f[1]=1; pow2[0]=1;
		for (int i=1; i<=n; ++i) pow2[i]=pow2[i-1]*3%mod;
		l1.add(l[1]+1, 1); l2.add(l[1]-1, 1); r1.add(r[1]-1, 1); r2.add(r[1]+1, 1);
		for (reg i=2,ls,rs,k; i<=n; ++i) {
			//cout<<"i: "<<i<<endl;
			//cout<<"ud: "<<up<<' '<<down<<endl;
			
			k=f[i-1];
			l1.add(l[i]+i, i); r1.add(r[i]-i, i);
			l2.upd(i); r2.upd(i);
			//++down;
			//cout<<"down: "<<down<<endl;
			//l2.add(l[down]-down, down); r2.add(r[down]+down, down);
			ls=max(l1.query()-i+k, max(max(l2.query(), l[down+1]-down-1), l[down+2]-down-2)+i+k);
			rs=min(r1.query()+i-k, min(min(r2.query(), r[down+1]+down+1), r[down+2]+down+2)-i-k);
			if (ls<=rs) {
				++down;
				//cout<<"down: "<<down<<endl;
				l2.add(l[down]-down, down); r2.add(r[down]+down, down);
				++down;
				//cout<<"down: "<<down<<endl;
				l2.add(l[down]-down, down); r2.add(r[down]+down, down);
				f[i]=k+1;
				continue;
			}
			//cout<<"ud2: "<<up<<' '<<down<<endl;
			
			k=f[i-1]-1;
			//cout<<"k2: "<<k<<endl;
			++up;
			l1.upd(up); r1.upd(up);
			ls=max(l1.query()-i+k, max(l2.query(), l[down+1]-down-1)+i+k);
			rs=min(r1.query()+i-k, min(r2.query(), r[down+1]+down+1)-i-k);
			//cout<<"rs: "<<r1.query()<<' '<<r2.query()<<endl;
			//cout<<"size: "<<r1.size()<<' '<<r2.size()<<endl;
			//cout<<"check2: "<<ls<<' '<<rs<<endl;
			if (ls<=rs) {
				f[i]=k+1;
				++down;
				//cout<<"down: "<<down<<endl;
				l2.add(l[down]-down, down); r2.add(r[down]+down, down);
				continue;
			}
			
			k=f[i-1]-2;
			++up;
			l1.upd(up); r1.upd(up);
			f[i]=k+1;
		}
		//cout<<"f: "; for (int i=1; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
		for (int i=1; i<=n; ++i) md(ans, pow2[i-1]*f[i]%mod);
		printf("%lld\n", ans);
		exit(0);
	}
}

signed main()
{
	cin>>n>>L>>X>>Y>>A>>B;
	gen(n, L, X, Y, A, B, l, r);
	//force::solve();
	//put();
	task::solve();
	
	return 0;
}
posted @ 2021-09-11 07:35  Administrator-09  阅读(13)  评论(0编辑  收藏  举报