蒟蒻养成记——数列变化(2)

Seq

2s

【题目描述】

给你一个序列,一开始只有一个0

接下来有n个操作,每个操作是下面3种操作描述的一种

1前ai个数全部加上xi

2在序列末尾加上ki这个数

3序列末尾删去一个数(所以序列的大小会减一)。只有序列里至少有2个数才执行这个操作

做完每一步,你需要输出这个序列的和的平均数

【输入格式】

第一行n

接下来n行,每行第一个数为ti(1<=ti<=3),为相应的操作编号

如果Ti=1,则跟着ai,xi(|xi|<=10^3;1<=ai)

如果Ti=2,则跟着ki(|ki|<=10^3)

如果ti=3,后面没有任何数

【输出格式】

输出n行,每行为每一次操作后序列每个数字的平均值,保留6位小数

【输入输出样例】

Input1

5
2 1
3
2 3
2 1
3

Output1

0.500000
0.000000
1.500000
1.333333
1.500000

Input1

6
2 1
1 2 20
2 2
1 2 -3
3
3

Output1

0.500000
20.500000
14.333333
12.333333
17.500000
17.000000

【数据解释】

第二个样例是这样子的

【数据约定】

40%数据:n<=5000

100%数据:1<=n<=2*10^5,保证操作合法性


【解法】

看到对数列的操作,第一反应想到线段数,树状数组。这些方法当然可以。

当然,今天我要讲的,是一种更加玄学的算法。

这种算法是线性的,所以每次操作是 o(1),故总的时间复杂度为  o(n)

现在讲讲这种算法:

首先开两个数组A和B。A用来存储初始数组,B表示数组修改的量。B【i】=u 表示从1到i加了u,因为每次只要查询最后一个数的值,所以那个值就是A【n】+B【n】

具体实现

Ti表示第i种操作

Ti=1:   B[ai]+=xi


Ti=2   :N++   A[n]=ki


Ti=3:   B[n-1]+=b[n]  N--

【PS】注意题目

3序列末尾删去一个数(所以序列的大小会减一)。只有序列里至少有2个数才执行这个操作

只有序列里至少有2个数才执行这个操作

只有序列里至少有2个数才执行这个操作

只有序列里至少有2个数才执行这个操作

只有序列里至少有2个数才执行这个操作


重要的事情,多说几遍


【代码】

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<iomanip>
using namespace std;
int a[200001];
int b[200001];
int i,j,k,m,n,o,p,js,jl,ai,xi;
int main()
{
FILE *fin,*fout;
fin=fopen("seq.in","rb");
fout=fopen("seq.out","wb");
fscanf(fin,"%d",&m);
js=0;
n=1;
for(int i=1;i<=m;i++)
{
fscanf(fin,"%d",&k);
if(k==1)
{
fscanf(fin,"%d%d",&ai,&xi);
b[ai]=b[ai]+xi;
js=js+ai*xi;
double jj=double(js)/n;
fprintf(fout,"%0.6llf\n",jj);
}
if(k==2)
{
fscanf(fin,"%d",&xi);
n++;
a[n]=xi;
js=js+xi;
double jj=double(js)/n;
fprintf(fout,"%0.6llf\n",jj);
}
if(k==3)
{
if(n>=2)
{
js=js-a[n]-b[n];
b[n-1]=b[n-1]+b[n];
b[n]=0;
n--;
}
double jj=double(js)/n;
fprintf(fout,"%0.6llf\n",jj);

}
}
fclose(fin);
fclose(fout);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值