2021秋 noip 模拟赛

9.9 T3 第负二题

\(f_i\) 的数学意义:中心在第 \(i\) 行的全 \(1\) 组成的最大正方形(对角线水平/竖直),对角线长 \(2f_i-1\)。

显然 \(f_i\) 具有单调性(存在较大的正方形则一定存在更小的)。由此得到一个朴素做法:
对于每行二分答案 \(k\),判断是否合法即判断是否存在合法的中心:

\[\max\{l_j+k-1+(i-j)\}\le\min\{r_j-k+1-(i-j)\},j\le i \]

\[\max\{l_j+k-1+(j-i)\}\le\min\{r_j-k+1-(j-i)\},j\ge i \]

发现两个 \(\max,\min\) 中与 \(j\) 相关的分别为 \(l_j-j,r_j+j,l_j+j,r_j-j\),RMQ 即可。
时间复杂度 \(O(n\log n)\)

另一个结论是 \(f_{i-1}-1\le f_i\le f_{i-1}+1\)(第 \(i-1\) 行变为 \(0\) 的下一时刻第 \(i\) 行一定都是 \(0\))。因此 \(k\) 不用二分,从 \(f_{i-1}-1\) 开始枚举即可,如果当前 \(k\) 不合法,则 \(f_i=k-1\),否则 \(k\leftarrow k+1\)。

考虑单调队列做到 \(O(n)\) RMQ。
对于 \(j\ge i\) 的情况,第 \(i-1\) 行 \(j\) 的区间为 \([i-1,(i-1)+(k+1)-1]\),扩展到第 \(i\) 行时变为 \([i,i+k-1]\),\(i,k\) 变大时左右端点都单调,普通单调队列。
对于 \(j\le i\),区间为 \([(i-1)-(k+1)+1,i-1]\) 变到 \([i-k+1,i]\),左端点不具有单调性。发现 \(k\) 最多变大两次,因此强制令左端点单调,对于没有考虑到的点(最多两个)特判即可。

code
const int N = 5e6+5, mod = 998244353;
int L,X,Y;
ULL A,B;

int n,m,l[N],r[N],f[N];
LL ans;

struct Que {
	int fro,rea,que[N];
	Que() { fro = 1, rea = 0; }
	int front() { return que[fro]; }
	int back() { return que[rea]; }
	void push_back(int x) { que[++rea] = x; }
	void pop_back() { --rea; }
	bool empty() { return fro>rea; }
	void valid(int l) { while( fro<=rea && que[fro] < l ) ++fro; }
} ul,ur,dl,dr;

namespace data {
typedef unsigned long long u64;
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 (int 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]); } }
}

signed main() {
	read(n,L,X,Y,A,B); data::gen(n,L,X,Y,A,B,l,r);
	f[1] = 1;
	For(i,2,n) For(k,max(f[i-1],2),f[i-1]+2) { int j = i+k-1;
		ul.valid(i-k+1), ur.valid(i-k+1), dl.valid(i), dr.valid(i);
		while( !ul.empty() && l[i]+i >= l[ul.back()]+ul.back() ) ul.pop_back();
		while( !ur.empty() && r[i]-i <= r[ur.back()]-ur.back() ) ur.pop_back();
		while( !dl.empty() && l[j]-j >= l[dl.back()]-dl.back() ) dl.pop_back();
		while( !dr.empty() && r[j]+j <= r[dr.back()]+dr.back() ) dr.pop_back();
		ul.push_back(i), ur.push_back(i), dl.push_back(j), dr.push_back(j);
		int le = l[ul.front()]+ul.front()-i+k-1,
			ri = r[ur.front()]-ur.front()+i-k+1;
		ckmax(le,l[dl.front()]-dl.front()+i+k-1),
		ckmin(ri,r[dr.front()]+dr.front()-i-k+1);
		if( k > f[i-1] )
			ckmax(le,l[i-k+1]+i-k+1-i+k-1), ckmin(ri,r[i-k+1]-(i-k+1)+i-k+1);
		if( k > f[i-1]+1 )
			ckmax(le,l[i-k+2]+i-k+2-i+k-1), ckmin(ri,r[i-k+2]-(i-k+2)+i-k+1);
		if( le > ri ) { f[i] = k-1; break; }
	}
	for(LL i = 1, pw = 1; i <= n; ++i, pw = pw*3%mod) ans += pw * f[i] %mod;
	write(ans%mod);
	return iocl();
}

上一篇:基于websocket实现消息中心


下一篇:7-15 深入虎穴 (25分)