1785 數據流中的算法(思路題,細心點就行了)

題目鏈接: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

關係M1=M2-z帶入得
ans1=(x1M2+z)2+.....+(xnM2+z)2

簡化:
ans1=(x1M2)2+.....+(xnM2)2+nzz+2z((x1M2)+....+(xnM2))

(x1M2)+....+(xnM2) 這一部分也可以像上面一樣更新。

這道題寫着很麻煩,所以要細心,本來以爲可以過,沒想到還是有兩處寫錯了。

下面是代碼:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章