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);
}