【JZOJ4585】Robert 的军队

Description

Solution

一开始以为这题是什么二分,数据结构之类的,结果推不出来。
后来推了大半天,才发现了用平方和和平均数来快速求方差,但是只把 O(n3) 化为了 O(n2)
没办法水了水,打了一个分段贪心,因为在对拍的时候发现选的数都只有l个。然后就变为 O(n) 了。结果,这种贪心是可以证明的,不过博主有点懒,不想打。

注意

这道题每个数的范围开的有点大,平方和会爆0x7fffffff(maxlongint),所以ans要开大一点。

注意c++的运算规律

比如说a=b*c,b*c会爆int,那么b和c都必须要开long long,除法类似。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100007;
long long i,j,k,l,t,n,m,r;
double ans,ave,pp;
long long a[maxn];
double sum[maxn],ans2;
double ping[maxn];
bool cmp(long long x,long long y){return x<y;}
int main(){
    freopen("army.in","r",stdin);
    freopen("army.out","w",stdout);
    scanf("%lld%lld%lld",&n,&l,&r);
    fo(i,1,n)scanf("%lld",&a[i]);
    sort(a+1,a+1+n,cmp);
    fo(i,1,n)ping[i]=a[i]*a[i]+ping[i-1],sum[i]+=sum[i-1]+a[i];ans=1000000000000000000;
    if(n<=2000){
        fo(i,1,n){
            fo(j,l,r){
                k=i+j-1;if(k>n)break;
                ave=sum[k]-sum[i-1];ave=ave/j;
                pp=ping[k]-ping[i-1];pp=pp/j-ave*ave;
                if(pp<ans){
                    ans=pp;
                }
            }
        }
    }
    else{
        fo(i,1,n){
            k=i+l-1;if(k>n)break;
            ave=sum[k]-sum[i-1];ave=ave/l;
            pp=ping[k]-ping[i-1];pp=pp/l-ave*ave;
            if(pp<ans){
                ans=pp;
            }
        }    
    }
    printf("%.3f\n",ans);
}

你可能感兴趣的:(贪心,平均数,方差,平方和,Robert的军队)