题目链接:1785 数据流中的算法
51nod近日上线了用户满意度检测工具,使用高级人工智能算法,通过用户访问时间、鼠标轨迹等特征计算用户对于网站的满意程度。
现有的统计工具只能统计某一个窗口中,用户的满意程度的均值。夹克老爷想让你为统计工具添加一个新feature,即在统计均值的同时,计算窗口中满意程度的标准差和中位数(均值需要向下取整)。
Input
第一行是整数n与k,代表有n次操作,时间窗口大小为k。
(1 <= n <= 10^6, 1 <= k <= 100)
接下来的n行,每行代表一次操作。操作有“用户访问”、“查询均值”、“查询方差”、“查询中位数”四种。每行的第一个数代表操作类型。
操作数1:用户访问
输入格式:<1, v>
用户的满意度v为闭区间[0, 100]中的任意整数。用户每访问一次,数据更新,移动统计窗口。
操作数2:查询均值
输入格式:<2>
统计窗口内的用户满意度的均值。
操作数3:查询方差
输入格式:<3>
统计窗口内用户满意度的方差
操作数4:查询中位数
输入格式:<4>
统计窗口内用户满意度的中位数
p.s. 在有查询请求时,窗口保证不为空
p.s.s. 有查询请求时,窗口可能不满
Output
对于“查询均值”、“查询方差”、“查询中位数”操作的结果,输出保留两位小数。
Input示例
12 3
1 1
1 2
1 3
2
3
4
1 4
1 5
1 6
2
3
4
Output示例
2.00
0.67
2.00
5.00
0.67
5.00
思路:说几个重要的点,他最多统计的是最近的k个用户的数据,时间更早的用户的数据会被挤掉,有个很坑的点给忘记了(这是我们错的两个点中的一个),均值要向下取整。其他的就按照题目描述即可。
还有一个点是在记录偶数的平均值的时候,记录的两个数据,有偏差。
欧对了,忘了一点,如何求解方差,方差
如何通过:以前的方差求解现在的方差?
我们只在这里记录方差上面的平方和(ans),设现在的平均数(M1)与上一个的平均数(M2),现在的ans为ans1,上一个的ans为ans2,就有关系M1=M2-z,所以
关系M1=M2-z带入得
简化:
(x1−M2)+....+(xn−M2) ( x 1 − M 2 ) + . . . . + ( x n − M 2 ) 这一部分也可以像上面一样更新。
这道题写着很麻烦,所以要细心,本来以为可以过,没想到还是有两处写错了。
下面是代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
typedef long long ll;
const int max2=1e6+9;
#define mem(a,b) memset(a,b,sizeof(a))
#define PI acos(-1.0)
int a[max2],b[109];
double ans1,ans2,ping,ans3;//下面加‘_’的与这意思一样,ans1记录方差上面的平方和,ans2记录xi-M的和,ans3最后k项用户的满意度,ping记录平均值
int inq;
int n,k,in;
void updata(int x)
{
inq++;
b[x]++;
double ping_,ans1_,ans2_,ans3_;//这是最新的数据
if(inq>k)//超过窗口的限制
{
//里面写的就有点复杂了,还是你慢慢看吧
b[a[inq-k]]--;
ping_=(ans3-a[inq-k]*1.0+x*1.0)/(k*1.0);
double cha=ping-ping_;
ans2_=ans2-(a[inq-k]-ping)+x-ping_+cha*(k-1);
ans1_=ans1-(a[inq-k]-ping)*(a[inq-k]-ping)+(x-ping_)*(x-ping_)+cha*cha*(k-1)+2.0*cha*(ans2-(a[inq-k]-ping));
ans3_=ans3-a[inq-k]+x;
//在这里将数据更新一下
ping=ping_;
ans3=ans3_;
ans1=ans1_;
ans2=ans2_;
}
else//与上面的相似
{
ping_=(ans3+x*1.0)/inq;
double cha=(ping-ping_);
ans2_=ans2+x-ping_+cha*(inq-1);
ans1_=ans1+cha*cha*(inq-1)+2*ans2*cha+(x-ping_)*(x-ping_);
ans3_=ans3+x;
ping=ping_;
ans3=ans3_;
ans1=ans1_;
ans2=ans2_;
}
a[inq]=x;
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
ans1=0,ans2=0,ping=0,inq=0,ans3=0;
mem(b,0);
while(n--)
{
int p,x;
scanf("%d",&p);
if(p==1)//更新所有数据
{
scanf("%d",&x);
updata(x);
}
else if(p==2)//均值,要向下取整(这是第一处错误)
{
in=min(inq,k);
int p=ans3/(in*1.0);
printf("%d.00\n",p);
}
else if(p==3)//方差
{
in=min(inq,k);
printf("%.2lf\n",ans1/(in*1.0));
}
else if(p==4)
{
in=min(inq,k);
double an;
if(in%2)//中位数有一个
{
int s=0;
for(int i=0; i<=100; i++)
{
s+=b[i];
if(s>in/2)
{
an=i;
break;
}
}
}
else//中位数有两个,就是这种情况记录错了(这是第二处错误),
{
an=0;
int s=0,flag=1;
for(int i=0; i<=100; i++)
{
if(b[i]==0) continue;
s+=b[i];
if(s>=in/2&&flag)//这里只能记录一次,当初就是这里错了,想哭
{
an+=i;
flag=0;
}
if(s>=in/2+1)
{
an+=i;
break;
}
}
an/=2.0;
}
printf("%.2lf\n",an);
}
}
}
return 0;
}