1785 数据流中的算法(思路题,细心点就行了)

119 篇文章 1 订阅
113 篇文章 1 订阅

题目链接: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,所以

ans1=(x1M1)2+.....+(xnM1)2 a n s 1 = ( x 1 − M 1 ) 2 + . . . . . + ( x n − M 1 ) 2

关系M1=M2-z带入得
ans1=(x1M2+z)2+.....+(xnM2+z)2 a n s 1 = ( x 1 − M 2 + z ) 2 + . . . . . + ( x n − M 2 + z ) 2

简化:
ans1=(x1M2)2+.....+(xnM2)2+nzz+2z((x1M2)+....+(xnM2)) a n s 1 = ( x 1 − M 2 ) 2 + . . . . . + ( x n − M 2 ) 2 + n ∗ z ∗ z + 2 ∗ z ∗ ( ( x 1 − M 2 ) + . . . . + ( x n − M 2 ) )

(x1M2)+....+(xnM2) ( 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值