[CSP-S 2019 D2T2]划分题解

(CSDN 是真的难看,广告好多QAQ,以后还是回洛谷和 cnblog 了)

Preface

这道题简直可以算卡常卡空间比赛了qwq,在线膜拜考场 AC 巨佬 Orz

Analysis

这道题和 [CF229D]Towers 可以说除了恶心人的数据几乎一模一样awa

  • 法一: 36 p t s 36pts 36pts

首先把前缀和数组 s s s 求出来。

对于 n ≤ 500 n \le 500 n500,显然直接用 O ( N 3 ) O(N^3) O(N3) 的区间 DP 即可。

  • 法二: 64 p t s 64pts 64pts

要想多骗点分,还需要观察出来一个性质:当最后一段尽量小的时候,答案一定最优。

这个性质虽然不一定能看出来,但应该都知道是为什么。

传统的区间 DP 显然过不了这题,考虑换一种 DP 状态:

d p ( i , j ) dp(i,j) dp(i,j) 表示当前第 i i i 个数所处的这一段开头为 j + 1 j + 1 j+1 时的最小答案。

则有 d p ( i , j ) = min ⁡ { d p ( j , k ) } + ( s i − s j ) 2 dp(i,j) = \min{\{dp(j,k) \}} + (s_i - s_j) ^ 2 dp(i,j)=min{dp(j,k)}+(sisj)2

其中 k k k 要满足 s j − s k ≤ s i − s j s_j - s_k \le s_i - s_j sjsksisj

虽然这样仍是 O ( N 3 ) O(N^3) O(N3) 的,但它有一些神奇的性质。

首先根据上述结论, k k k 越大, d p ( j , k ) dp(j,k) dp(j,k) 越小,而且 s j − s k s_j - s_k sjsk 会越小,满足上式的可能性越高。

考虑建立一个数组 p o s pos pos,令 p o s j pos_j posj 为使得 d p ( j , k ) dp(j,k) dp(j,k) 最小的 k k k 的取值。

这时发现可以将 d p dp dp 改为一维, d p ( i ) dp(i) dp(i) 表示 1 ∼ i 1 \sim i 1i 的最优划分值。

从大到小枚举 j j j,若满足 s j − s p o s j ≤ s i − s j s_j - s_{pos_j} \le s_i - s_j sjsposjsisj,则 d p ( i ) = d p ( j ) + ( s i − s j ) 2 dp(i) = dp(j) + (s_i - s_j) ^ 2 dp(i)=dp(j)+(sisj)2

然后记录一下这个取值,即 p o s i = j pos_i = j posi=j,目标状态即为 d p ( n ) dp(n) dp(n)

时间复杂度: O ( N 2 ) O(N^2) O(N2)

到这个时候我们已经可以拿到 64 p t s 64 pts 64pts 的大众分了awa

接下来 n = 5 × 1 0 5 n = 5 \times 10^5 n=5×105 是给 O ( N log ⁡ N ) O(N\log N) O(NlogN) 的决策单调性做法的,然鹅我并不会那种东西 QAQ,有兴趣可以去 [CF229D]Towers 这个题的题解里看看。

下面直接开始正解。

  • 法三: 100 p t s 100 pts 100pts

发现限制我们的是 s j − s p o s j ≤ s i − s j s_j - s_{pos_j} \le s_i - s_j sjsposjsisj 这个东西,考虑把能一起维护的放到一边:

2 × s j − s p o s j ≤ s i 2 \times s_j - s_{pos_j} \le s_i 2×sjsposjsi

对于每个 i i i,求出最近的满足这个式子的 j j j 即可。

n = 4 × 1 0 7 n = 4 \times 10^7 n=4×107 的恐怖范围,加上 s i s_i si 具有单调性,不难想到可以用单调队列优化~

但我们平常学到的都是求最小,怎么求最近呢?

可以用类似滑动窗口的思路解决,两头同时更新。

具体思路是仍照常维护一个 2 × s j − s p o s j 2 \times s_j - s_{pos_j} 2×sjsposj 单调递增的队列。

在扫到一个 i i i 时,处理一下队首,如果队首和队首后面的元素同时满足这个限制,那么两者一定都能满足 i + 1 ∼ n i+1\sim n i+1n 的限制,而且后面这个元素一定比队首晚入队,更优。

那么这个时候,我还要你队首干什么呢?

这就是我们常说的,如果一个选手比你小还比你强,那么你就可以退役了o(╥﹏╥)o

直接删去队首,继续判断直到队列元素数 ≤ 1 \le 1 1 或者不满足这个条件即可。

其他就和普通的单调队列没区别了 (**)

注意的是这题卡时空限制,而且要用 int128 或者高精度,而且 d p dp dp 数组开不下。

只能把 p o s pos pos 数组处理出来,最后统一计算输出QAQ

时间复杂度: O ( N ) O(N) O(N)

#include <bits/stdc++.h>
#define LL __int128
using namespace std;
const int maxn = 4e7 + 5;
const int maxm = 1e5 +5;
typedef long long ll;
LL read() {
	LL s = 0,f = 1;
	char c = getchar();
	for(;!isdigit(c);c = getchar())
		if(c == '-')f = -1;
	for(;isdigit(c);c = getchar())s = (s << 1) + (s << 3) + (c ^ '0');
	return s * f;
}
void write(LL x) {
	if(x < 0) {
		putchar('-');
		x = -x;
	}
	if(x > 9)write(x / 10);
	putchar(x % 10 + '0');
	return ;
}
int x,y,z;
int b[maxn];
ll s[maxn];
int a[maxn],m,n,pos[maxn];
int p[maxm],l[maxm],r[maxm];
int q[maxn],head,tail;
ll SUM(int x) {
	return s[x] - s[pos[x]] + s[x];
}
void datamaker() {
	scanf("%d%d%d%d%d%d",&x,&y,&z,&b[1],&b[2],&m);
	for(int i = 1;i <= m;++ i)scanf("%d%d%d",&p[i],&l[i],&r[i]);
	for(int i = 3;i <= n;++ i)b[i] = (x * b[i - 1] + y * b[i - 2] + z) & ((1 << 30) - 1);
	for(int j = 1;j <= m;++ j) {
		for(int i = p[j - 1] + 1;i <= p[j];++ i) {
			a[i] = (b[i] % (r[j] - l[j] + 1)) + l[j];
			s[i] = s[i - 1] + a[i]; 
		}
	}
	return ;
}
int main() {
	int tp;
	scanf("%d%d",&n,&tp);
	if(tp)datamaker();
	else for(int i = 1;i <= n;++ i)scanf("%d",&a[i]),s[i] = s[i - 1] + a[i];
	q[head = tail = 1] = 0;
	for(int i = 1;i <= n;++ i) {
		for(;head < tail&&SUM(q[head]) <= s[i]&&SUM(q[head + 1]) <= s[i];)q[head ++] = 0;
		pos[i] = q[head];
		for(;head < tail&&SUM(q[tail]) >= SUM(i);)q[tail --] = 0;
		q[++ tail] = i;
	}
	LL ans = 0;
	for(int cur = n;cur;cur = pos[cur])ans += ((LL)(s[cur] - s[pos[cur]]) * (s[cur] - s[pos[cur]]));
	write(ans);
	return 0;
}

完结撒花★,°:.☆( ̄▽ ̄)/$:.°★

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值