专栏文章

题解 CF2094G

CF2094G题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipgmwm8
此快照首次捕获于
2025/12/03 11:41
3 个月前
此快照最后确认于
2025/12/03 11:41
3 个月前
查看原文

题意

给定一个数组 aa,有三类操作:翻转、循环移位和在末尾插入。每次操作后求 i=0naii\sum_{i=0}^n a_i\cdot i

思路

乍一看可能要高级数据结构维护,但其实所有操作都可以 O(1)O(1) 完成。
我们维护一个当前状态的答案 ansans 和所有数组元素之和 sumsum,每次操作时如下更新即可:
  • 操作一,ansi=0n1ai(n1)an=ans+sumannans\leftarrow \sum_{i=0}^{n-1}a_i-(n-1)\cdot a_n=ans+sum-a_n\cdot n
  • 操作二,ansni=0naians=sum(n+1)ansans\leftarrow n\cdot \sum_{i=0}^{n}a_i-ans=sum\cdot (n+1)-ans
  • 操作三,ansans+(n+1)k; sumsum+kans\leftarrow ans+(n+1)\cdot k;\ sum\leftarrow sum+k
当然这是对答案的维护。对于数组本身的维护,显然不能直接使用数组暴力修改,考虑使用队列。而由于有翻转操作的存在,队列两端都可以增添元素,因此我们可以请出 STL 的好工具,双端队列 deque。
deque 支持从头部和尾部增添或者删除元素,维护一个 bool 值表示当前处于正方向还是反方向,每次采用该方向的方式维护双端队列即可。

程序如下

CPP
#include<cstdio>
#include<cstring>
#include<deque>
using namespace std;
int T,m;
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d",&m);
		deque<int>q;
		bool inv=false;
		long long ans=0,sum=0;
		int n=0;
		while(m--){
			int op,x;
			scanf("%d",&op);
			if(op==1){
				int k;
				if(inv){
					k=q.front();
					q.pop_front();
					q.push_back(k);
				}
				else{
					k=q.back();
					q.pop_back();
					q.push_front(k);
				}
				ans=ans+sum-1ll*n*k;
			}
			else if(op==2){
				inv=!inv;
				ans=1ll*(n+1)*sum-ans;
			}
			else{
				scanf("%d",&x);
				if(inv)q.push_front(x);
				else q.push_back(x);
				ans+=1ll*++n*x;
				sum+=x;
			}
			printf("%lld\n",ans);
		}
	}
	return 0;
}

THE END

评论

0 条评论,欢迎与作者交流。

正在加载评论...