首页 > 其他分享 >洛谷 P11012 颜料

洛谷 P11012 颜料

时间:2024-08-31 14:04:47浏览次数:12  
标签:ch 洛谷 删除 min 颜料 绚丽 num 贡献 P11012

洛谷 P11012 颜料

题意

给出长度为 \(n\) 的序列 \(a\)。定义一段区间 \([l,r]\) 的绚丽程度 \(X_{l,r}\) 为 \(\sum_{i=1}^{W}\sum_{j=i+1}^W\min(c_i,c_j)\),其中 \(W\) 是值域,\(c_i\) 表示 \(a\) 序列 \([l,r]\) 中 \(i\) 出现的次数,求绚丽程度至少为 \(k\) 的区间长度最小值。

思路

考虑固定右端点 \(r\),对于 \(l_1<l_2\) 有 \(X_{l_1,r} \ge X_{l_2,r}\)。

考虑固定左端点 \(l\),对于 \(r_1<r_2\) 有 \(X_{l,r_1} \le X_{l,r_2}\)。

可以使用双指针求出最短的区间 \([l,r]\)。

对于每个 \(r\),若当前 \([l,r]\) 绚丽程度大于 \(k\),\(l\) 向右移动直到不能再动,统计答案后,\(r\) 向右移动。

我们需要一种快速的方式更新区间的绚丽程度。

由于双指针每次只删除或增加一个数,我们考虑如何快速统计增加或删除一个数的贡献。

对于一个数 \(x\),记 \(s\) 为小于 \(x\) 的数的和,记 \(C\) 为在 \([x,W]\) 内的数的个数。

则 \(x\) 对绚丽程度的贡献为 \(s + (C-1)x\)。

因为小于 \(x\) 的数和 \(x\) 取 \(\min\) 结果为本身,大于等于 \(x\) 的数和 \(x\) 取 \(\min\) 结果为 \(x\),减 \(1\) 是减去 \(x\) 本身。

动态维护这些值可以使用权值树状数组或权值线段树。

加入一个数 \(num\) 时,删除 \(c_{num}\) 的贡献,将 \(c_{num}\) 加一,加入 \(c_{num}\) 的贡献。

删除一个数 \(num\) 时,删除 \(c_{num}\) 的贡献,将 \(c_{num}\) 减一,加入 \(c_{num}\) 的贡献。

同时动态维护上面的所有值。

开两棵树状数组,一棵维护和,一棵维护个数即可。

时间复杂度:\(O(n\log n)\)。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e6 + 5;
int n, W, k, a[N], c[N], val;
template <typename T> inline  void read(T& x) {
	x = 0;
	char ch = getchar();
	while (ch < '0' || ch > '9') ch = getchar();
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
}
struct BIT {
	int t[N];
	void clear() {
		memset(t, 0, sizeof(t));
	}
	void add(int x, int y) {
		for (int i = x; i <= W; i += i & (-i)) t[i] += y;
	}
	int query(int x) {
		int res = 0;
		for (int i = x; i; i -= i & (-i)) res += t[i];
		return res;
	}
	int query(int x, int y) {
		return query(y) - query(x - 1);
	}
} T1, T2;
// T1 维护和
// T2 维护个数
int calc(int num) { // num 的贡献
	int res = 0;
	res += T1.query(num - 1);
	res += num * (T2.query(num, W) - 1);
	return res;
}
void del(int num) { // 删数
	val -= calc(c[num]); // 删除旧贡献
	T1.add(c[num], -c[num]); // 维护树状数组
	T2.add(c[num], -1);
	c[num] --; // 更改 c[num]
	if (c[num]) { // 加入新贡献
		T1.add(c[num], c[num]);
		T2.add(c[num], 1);
		val += calc(c[num]);
	}
}
void add(int num) { // 加数
	if (c[num]) { // 删除旧贡献
		val -= calc(c[num]); // 维护树状数组
		T1.add(c[num], -c[num]);
		T2.add(c[num], -1);
	}
	c[num] ++; // 更改 c[num]
	T1.add(c[num], c[num]); // 加入新贡献
	T2.add(c[num], 1);
	val += calc(c[num]);
}
signed main() {
	read(n), read(k);
	for (int i = 1; i <= n; i ++) read(a[i]), W = max(a[i], W);
	int l = 1, res = 1e9;
	for (int i = 1; i <= n; i ++) {
		add(a[i]); // 加入 i
		while (val >= k) { // 向右移动 l
			del(a[l ++]);
			if (val < k) { // 移不动了
				add(a[-- l]);
				break;	
			}
		}
		if (val >= k) res = min(res, i - l + 1); // 统计答案
	}
	if (res == 1e9) cout << -1;
	else cout << res;
	return 0;
}

标签:ch,洛谷,删除,min,颜料,绚丽,num,贡献,P11012
From: https://www.cnblogs.com/maniubi/p/18390208

相关文章

  • 洛谷 P11011 点的覆盖
    洛谷P11011点的覆盖题意给定一个四边平行于坐标轴的矩形\(A\),给定\(n\)个在矩形\(A\)内部(可能在边缘上)的点。求有多少个\(A\)的子矩形覆盖了所有\(n\)个点(允许在边缘上)。所有坐标都是整数。思路求出:\(X_1=\max_{i=1}^nx_i\),\(X_2=\min_{i=1}^nx_i\),\(Y_1=\max_......
  • 洛谷题单指南-常见优化技巧-P1950 长方形
    原题链接:https://www.luogu.com.cn/problem/P1950题意解读:在一张n*m个格子的纸上,从没有画过的格子中剪出长方形的方案数。解题思路:1、暴力做法枚举所有的子矩阵O(n^4),然后用二维前缀和计算子矩阵的和,通过和来判断子矩阵是否全部是'.'。2、优化做法针对每一行进行处理,计算包......
  • 洛谷 P2680 [NOIP2015 提高组] 运输计划
    洛谷P2680[NOIP2015提高组]运输计划题意给出一棵树和\(m\)条路径,可以选择一条边,把边权改为\(0\),求\(m\)条路经长度最大值的最小值。思路看到最大值最小,可以想到二分答案,答案具有单调性。考虑如何判定答案\(x\)是否可行。统计所有长度大于\(x\)的路径,统计它们共......
  • 洛谷P5322 [BJOI2019] 排兵布阵 题解
    代码#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongintdp[20001],a[101][101],s,n,m;signedmain(){ cin>>s>>n>>m; for(intj=1;j<=s;j++){ for(inti=1;i<=n;i++){ cin>>a[i][j]; } } for(inti=1;......
  • 洛谷P9751 [CSP-J 2023] 旅游巴士
    传送门:P9751[CSP-J2023]旅游巴士为了那个梦我们扬帆起航,为了理所到来的那天跨越无尽黑夜由于这几天做的题目太少,我用小号立下flag:导致果然做了一晚上。。。。并且最后还是没做出来被我妈强制去睡觉了题目意思:题目很明白了,这里说几个要注意的点:道路均只能单向通行到......
  • 洛谷 P3128 [USACO15DEC] Max Flow P
    洛谷P3128[USACO15DEC]MaxFlowP题意给定一棵\(n\)个点的树,给定\(k\)个点对\((u,v)\),把\(u\)到\(v\)路径上所有点的点权加一,最后求最大点权。思路树上差分模版。维护\(a_i\)表示每个点到根的加法标记。对于每个点对\((u,v)\),把\(a_u\),\(a_v\)加一,\(a_{LCA......
  • 洛谷P4163[SCOI2007]排列
    洛谷P4163[SCOI2007]排列题意给一个数字串\(s\)和正整数\(d\),统计\(s\)有多少种不同的排列能被\(d\)整除(可以有前导\(0\))。思路考虑状压dp。\(dp_{S,k}\)表示当前已经选定了\(S\)集合(下标)的数,模\(d=k\)的方案数。状态转移方程:\[dp_{S|2^j,(k\times10+s_j)......
  • 洛谷P10931 闇の連鎖
    洛谷P10931闇の連鎖题意给定一棵\(n\)个点的树,有\(m\)条附加边。第一次删除一条树边,第二次删除一条附加边。求有多少种方案使原来的树不联通。思路考虑求出\(f_i\)表示\(i\)的子树中有多少条附加边连向\(i\)的子树外。若\(f_i=0\),则把\(i\)与\(i\)的父亲之间......
  • 洛谷 P1518 [USACO2.4] 两只塔姆沃斯牛 The Tamworth Two
    [USACO2.4]两只塔姆沃斯牛TheTamworthTwo题目描述两只牛逃跑到了森林里。FarmerJohn开始用他的专家技术追捕这两头牛。你的任务是模拟他们的行为(牛和John)。追击在10×......
  • 洛谷SCP 2024 第一轮(初赛 J 组)模拟题解析(第三部分:完善程序(1-2))
    完善程序一(补全)#include<bits/stdc++.h>usingnamespacestd;constintMAXN=100000;intn;intvis[MAXN],a[MAXN];vector<int>ans;intcheck(intk){intx=n,top=0;for(inti=0;i<=k;i++)vis[i]=0;while(x......