7th.Mar.2019

T1

1208065-20190307213436947-1759020117.png

  • 这题真的神题吧,看完题目只会最短路和暴力dp,但不幸,一分也没有。
  • 题解挂上算了……

1208065-20190307213604482-1397878295.png

T2

1208065-20190307213745232-441587954.png

  • 相比第一题,这个题就有点水了。(不过说实话自己是大力猜结论,合理对拍,成功找到正解结论)。
  • 对原序列先从小到大排序。考虑要求平均数-中位数最大值,那么奇数个数的集合肯定比偶数个数的集合更优一些。这就是那个大胆的结论,正是有了它,我们才可以摆脱\(2^n\)枚举的魔咒!
  • 我们已经知道了集合个数为奇数,显然可以枚举中位数。比较好想的是,我们枚举了中位数,再枚举一个长度,那么当前最优的取法已经确定。在中位数左边的数去靠右的,在中位数右边的也取靠右的。这样一定是最优的。
  • 但是这样是\(n^2\)的,60分。要说暴力分挺足的,但是既然想到了这一步,再想不到二分就有点sb了吧。(实锤我就是那个sb)。你中位数已经确定了,你取的方案也知道了,靠右取。那么随着长度越来越长,一定会有一个分界点,使得平均数开始减小。二分这个分界点,就ok了。复杂度\(n*log_n\)。愉快Ac!
  • 代码合理分治数据,稳!
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=2e5+10;ll sum[N];
int n,a[N],b[N];double ans;
double c,d;
void check(int top){
    int c[N];
    for(int i=1;i<=top;++i) c[i]=b[i];
    sort(c+1,c+top+1);
    double temp;
    if(top%2==1) temp=c[top/2+1];
    else temp=1.0*(c[top/2]+c[top/2+1])/2;
    double res=0;
    for(int i=1;i<=top;++i) res+=c[i];
    res=1.0*res/top;
    ans=max(ans,res-temp);
}
void dfs(int x,int top){
    if(x==n+1){
        check(top-1);
        return ;
    }
    b[top]=a[x];
    dfs(x+1,top+1);
    b[top]=0;
    dfs(x+1,top);
}
bool check1(int i,int mid){
    c=1.0*(sum[i-1]-sum[i-mid-1]+sum[n]-sum[n-mid]+a[i])/(2*mid+1)-a[i];
    d=1.0*(sum[i-1]-sum[i-mid]+sum[n]-sum[n-mid+1]+a[i])/(2*mid-1)-a[i];
    if(c<d) return 1;
    else return 0;
}
int main(){
    freopen("subset.in","r",stdin);
    freopen("subset.out","w",stdout);
    scanf("%d",&n);
    for(int i=1;i<=n;++i) scanf("%d",&a[i]);
    if(n<=20){
        dfs(1,1);
        printf("%.5lf\n",ans);
    }else if(n<=2000){
        sort(a+1,a+n+1);for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
        for(int i=1;i<=n;++i){//i是当前中位数 
            for(int l=1;l<=min(i-1,n-i);++l){
                ans=max(ans,1.0*(sum[i-1]-sum[i-1-l]+sum[n]-sum[n-l]+a[i])/(2*l+1)-a[i]);
            }
        }
        printf("%.5lf\n",ans);  
    }else{
        sort(a+1,a+n+1);for(int i=1;i<=n;++i) sum[i]=sum[i-1]+a[i];
        for(int i=1;i<=n;++i){//i是当前中位数 
            int l=1,r=min(i-1,n-i);
            while(l+1<r){
                int mid=l+r>>1;
                if(check1(i,mid)) r=mid;
                else l=mid;
            }
            if(check1(i,r)) ans=max(ans,d);
            else ans=max(ans,c);
        }
        printf("%.5lf\n",ans);
    }
    return 0;
}
T3

看完题目,完了。AC自动机+dp+期望+高斯消元,爆零吧。(哭了)

speech.gif posted on 2019-03-07 21:52 kgxpbqbyt 阅读( ...) 评论( ...) 编辑 收藏
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值