石中集训8.9测试 T4 奶牛

考场上写了 80 分的暴力,但离正解真的很近。只需要用一点初中(小学生也会)的知识正解了。

题意

有一个长度为 nn 的序列 aa。你可以将 xx 插入在 aa 的任意位置。定义 bb 为插入 xx 的新序列。定义 s(b)=l=1,r=mrn+1maxi=lir{ai}s(b)=\sum\limits^{r\leq n+1}_{l=1,r=m}\max\limits^{i\leq r}_{i=l}\{a_i\}。求最大的 s(b)s(b)

或者可以这样:

maxi=0nj=1nm+2maxk=jj+m1{xk=i+1ak1ji+1&k>iakotherwise\max\limits_{i=0}^n\sum\limits_{j=1}^{n-m+2}\max\limits_{k=j}^{j+m-1}\begin{cases}x &k=i+1 &\\ a_{k-1} &j\le i+1 \And k>i \\ a_k & otherwise\end{cases}

很明显根本看不懂。

输入格式

n m x
a1,a2,a3...an

思路

先从暴力讲起。枚举将 xx 插入在 aia_iai+1a_{i+1}。也即枚举 bb 序列。然后可以用单调队列求定长区间最值。复杂度 O(n2)O(n^2)

但是这样要求在线,也就是说这样写的复杂度无法改变。

观察每个区间最值,我们可以分成三类。

  1. xx 影响了的区间。
  2. 和原来一样的区间。
  3. 新加入的区间。

举个例子。

3 2 50

60 100 70

假设将 5050 插入在 6060 后。序列变成:

60 50 100 70
  1. [60,50][60,50] 是被影响的区间;
  2. [100,70][100,70] 是原本的区间;
  3. [50,100][50,100] 是新加入的区间;

ii 为在 ai,ai+1a_i,a_{i+1} 插入 xx。就可以遍历区间起点 jjnm+1j|j\leq n-m+1,判断区间的类型求解。

被影响的区间满足 ji&j+m1>ij\leq i \And j+m-1> i,包含原序列中 [j,j+m2][j,j+m-2](最后的数被 xx 替代了)。

原本的区间有两种,在 xx 前与后,分别满足 j+m1i,j>ij+m-1\le i,j>i,区间仍为 [j,j+m1][j,j+m-1]

新加入的区间分成两类,其一是以 xx 为起点的。包含原序列中的 [j+1,j+m1][j+1,j+m-1](xx 代替 aia_i)。
当然,若不能以 xx 为起点,即 j+m1>nj+m-1>n 时,区间以 aa 序列元素为起点。该区间包含原序列中的 [nm+2,n][n-m+2,n],另外,除原序列以外,还包括 xx

对于原数列的区间最值,可以用 st 表求解。

时间复杂度 O(n2)O(n^2)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10;
int n,m,a[N],st[N][25],c[N],d[N],s[N],lg[N],cval;
void init() {
	for(int i=2;i<=n;i++) {
		lg[i]=lg[i>>1]+1;
	}
	for(int j=1;j<=24;j++) {
		for(int i=1;i+(1<<j)-1<=n;i++) {
			st[i][j]=max(st[i][j-1],st[i+(1<<(j-1))][j-1]);
		}
	}
}
int ans(int l,int r) {
	int len=lg[r-l+1];
	return max(st[l][len],st[r-(1<<len)+1][len]);
}
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>cval;
	for(int i=1;i<=n;i++) {
		cin>>a[i];
		st[i][0]=a[i];
	}
	init();
	int sum=0,as=0;
	for(int i=0;i<=n;i++) {//i~i+1
		sum=0;
		if(i+m-1<=n)sum=max(cval,(i+1<=i+m-1)?ans(i+1,i+m-1):0);
		else
			sum=max((n-m+2<=n)?ans(n-m+2,n):0,cval);
		for(int j=1;j+m-1<=n;j++) {//起点 
			if((j<=i&&j+m-1>i)) {
				sum+=max(ans(j,j+m-2),cval);
			}
			else
			if(j+m-1<=i) {
				sum+=ans(j,j+m-1);
			}
			else
			if(j>i) {
				sum+=ans(j,j+m-1);
			}
		}
		as=max(sum,as);
	}
	cout<<as;
	return 0;
}

但是这样的时间复杂度不足通过本题。
考虑优化。被影响的区间,不被影响的区间都是连续的。倘若我们解不等式组,可以得到不同种区间的取值范围。

  • 对于被影响的区间:
posted @ 2023-08-09 20:27  cjrqwq  阅读(7)  评论(0)    收藏  举报  来源