当前位置: 首页 > article >正文

【题解】CF2009G1

前言

  只会做G1 ,但尽量做到最好,除了一开始的排序的O(nlogn),后续处理都是O(n)。可能会对G2和G3有一点点用处。

翻译

原题链接CF2009G1
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

  直接处理等差数列不方便,但这个等差数列性质特殊,即公差为1。所以在一个等差数列中, a [ i ] − i a[i]-i a[i]i就成了常数列。为了避免出现负数,我们将 a [ i ] a[i] a[i]更改为 a [ i ] + n − i a[i]+n-i a[i]+ni,然后问题转化为将这个长度为 k k k的数列转变为常数列的最小操作次数,易知等价于 k − k- k众数 的数量。

  我们使用滑动窗口,维护所有数量,数量的降序映射数组,和降序数组中数量相同的区间的左右边界。各种映射非常复杂,调了好久,下面举个例子:

  现在数组为 1 , 1 , 2 , 2 , 1 , 4 , 2 1,1,2,2,1,4,2 1,1,2,2,1,4,2
  数量数组为 3 , 3 , 0 , 1 3,3,0,1 3,3,0,1
  降序数组为 1 , 2 , 4 , 3 1,2,4,3 1,2,4,3
  边界为: [ 1 , 2 ] , [ 3 , 3 ] , [ 4 , 4 ] [1,2], [3,3],[4,4] [1,2],[3,3],[4,4]

  要维护这么多东西的目的就是让窗口滑动时,新增数据和删除数据的维护代价为O(1)。这是因为每次改变时,一个值对应的数量只会 + 1 +1 +1 − 1 -1 1。假如数量由 3 3 3变成了 4 4 4,那么交换自己和 3 3 3的左边界,然后调整一下 3 3 3 4 4 4的边界即可。

  最后,每次的答案就是数量数组第一个中对应的值。

代码

  尽量注释了,真太难说清楚了。把我注释的调试代码复原更好理解。

#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;
int n, k, q, a[N];
// cnt[值] =  值的数量 
// id[i] = cnt中数量第i多的值 
// re_id[值] = 这个值是第几多的 
// l[数量], r[数量] = 同样数量在id中的边界 
int cnt[2*N], id[2*N], re_id[2*N], ans[N];
int l[2*N], r[2*N];   // 每一种数量在id中的左右边界 
bool cmp(int x, int y) {
	return cnt[x] > cnt[y];
}
signed main() {
	int t; cin>>t;
	while(t--) {
		cin>>n>>k>>q;
		for(int i=0;i<=2*n;i++) {
			cnt[i] = 0;
			id[i] = i;
		}
		for(int i=1;i<=n;i++) {
			cin>>a[i];
			a[i] = a[i] + n - i;
		}
//		cout<<"a: "; for(int j=1;j<=n;j++) cout<<a[j]<<' '; cout<<endl;
		
		for(int i=1;i<=k;i++) {     // 初始化数量数组 
			cnt[a[i]]++;
		}
		sort(id+1, id+2*n+1, cmp);  // 初始化有序化数组id 
		for(int i=0;i<=2*n;i++) re_id[id[i]] = i;   // 初始化re_id 
		ans[k] = cnt[id[1]];
		for(int i=0;i<=2*n;i++) l[i] = r[i] = -1;   // 初始化l, r 
		for(int i=1;i<=2*n;i++) {    // 初始化边界维护数组 
			if(cnt[id[i]] != cnt[id[i-1]]) {
				l[cnt[id[i]]] = i;
				r[cnt[id[i]]] = i;
			} else {
				r[cnt[id[i]]] = i;
			}
		} 
		for(int i=k+1;i<=n;i++) {
//			cout<<endl;
//			cout<<"a_now: "; for(int j=i-k;j<=i-1;j++) cout<<a[j]<<' '; cout<<endl;
//			cout<<"cnt: "; for(int j=1;j<=2*n;j++) cout<<cnt[j]<<' '; cout<<endl;
//			cout<<"id: "; for(int j=1;j<=2*n;j++) cout<<id[j]<<' '; cout<<endl;
//			cout<<"re_id: "; for(int j=1;j<=2*n;j++) cout<<re_id[j]<<' '; cout<<endl;
//			cout<<"cnt[id]: "; for(int j=1;j<=2*n;j++) cout<<cnt[id[j]]<<' '; cout<<endl;
//			cout<<"l: "; for(int j=0;j<=2*n;j++) cout<<l[j]<<' '; cout<<endl;
//			cout<<"r: "; for(int j=0;j<=2*n;j++) cout<<r[j]<<' '; cout<<endl;
//			cout<<"ans: "<<ans[i-1]<<endl;
			int now = a[i];   // 当前值 
			int cnt_now = cnt[now];    // 当前数量 
			int tl = l[cnt_now], id_tl = id[tl];  // 边界,边界对应的值
			swap(id[tl], id[re_id[now]]);
			
			re_id[id_tl] = re_id[now];
			re_id[now] = tl;
			
			if(l[cnt_now] == r[cnt_now]) {
				l[cnt_now] = r[cnt_now] = -1;
			} else {
				l[cnt_now] ++;
			}
			
			if(r[cnt_now+1] == -1) {
				l[cnt_now+1] = r[cnt_now+1] = tl;
			} else {
				r[cnt_now+1] ++;
			}
			
			cnt[now] ++;
			
			now = a[i-k];  
			cnt_now = cnt[now];
			int tr = r[cnt_now], id_tr = id[tr];
			swap(id[tr], id[re_id[now]]);
			
			re_id[id_tr] = re_id[now];
			re_id[now] = tr;
			
			if(l[cnt_now] == r[cnt_now]) {
				l[cnt_now] = r[cnt_now] = -1;
			} else {
				r[cnt_now] --;
			}
			
			if(l[cnt_now-1] == -1) {
				l[cnt_now-1] = r[cnt_now-1] = tr;
			} else {
				l[cnt_now-1] --;
			}
			cnt[now] --;
			
			ans[i] = cnt[id[1]];
		} 
//		cout<<endl;
//		cout<<"a_now: "; for(int j=n-k+1;j<=n;j++) cout<<a[j]<<' '; cout<<endl;
//		cout<<"cnt: "; for(int j=1;j<=2*n;j++) cout<<cnt[j]<<' '; cout<<endl;
//		cout<<"id: "; for(int j=1;j<=2*n;j++) cout<<id[j]<<' '; cout<<endl;
//		cout<<"re_id: "; for(int j=1;j<=2*n;j++) cout<<re_id[j]<<' '; cout<<endl;
//		cout<<"cnt[id]: "; for(int j=1;j<=2*n;j++) cout<<cnt[id[j]]<<' '; cout<<endl;
//		cout<<"l: "; for(int j=0;j<=2*n;j++) cout<<l[j]<<' '; cout<<endl;
//		cout<<"r: "; for(int j=0;j<=2*n;j++) cout<<r[j]<<' '; cout<<endl;
//		cout<<"ans: "<<ans[n]<<endl;
		for(int d=1;d<=q;d++){
			int L, R; 
			cin>>L>>R;
			R = L+k-1;
			cout<<k - ans[R]<<endl;
		}
	}
}

http://www.kler.cn/news/308658.html

相关文章:

  • QtC++截图支持获取鼠标光标
  • 运维工程师面试整理-虚拟化与容器
  • 实时数仓3.0DWD层
  • vulnhub(7):Toppo(经典的suid滥用提权)
  • ArcGIS Pro SDK (十四)地图探索 1 地图视图
  • 探索 InternLM 模型能力边界
  • 什么是外贸专用路由器?
  • 后端开发 每天六道面试题之打卡第一天
  • python中的各类比较与计算
  • Android14 蓝牙 BluetoothService 启动和相关代码介绍
  • 【Vue】- 生命周期和数据请求案例分析
  • phpstudy 建站使用 php8版本打开 phpMyAdmin后台出现网页提示致命错误:(phpMyAdmin这是版本问题导致的)
  • k8s中的存储
  • 【设计模式-外观】
  • 【计算机网络 - 基础问题】每日 3 题(七)
  • 【编译原理】看书笔记
  • keep-alive缓存不了iframe
  • 快速开发与维护:探索 AndroidAnnotations
  • Edegex Foundry docker和源码安装
  • uniapp与webview进行数据通信
  • 每个电脑都有ip地址吗?不同电脑ip地址一样吗
  • 爬虫代理失效怎么处理?全面解决方案
  • 【智路】智路OS 设备接入开发
  • 力扣122.-买卖股票的最佳时机 II(Java详细题解)
  • Python数据分析 Pandas基本操作
  • .NET 6.0 + WPF 使用 Prism 框架实现导航
  • Linux下编译Kratos
  • 如何动态获取路由上的参数
  • 最短路径算法
  • 详解QT元对象系统用法