ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

[游记]2022年多校冲刺NOIP联训测试4-2022.7.22

2022-07-22 21:02:51  阅读:123  来源: 互联网

标签:ch NOIP 22 int double eps 联训 WR include


立字为证:如果再用 $const int eps$ 就砸掉自己的电脑!!!

 

A. 甲国的军队

B. 虚弱

C. 萨鲁曼的半兽人

D. 序列

嗯,因为 $const int eps=1e-10$ 送掉一道题的分数

开心至极

总分 $160/400$

截图不太好截,不搞了(

 

A. 甲国的军队

首先考虑到对于整个战斗过程,$\sum\limits_{i=1}^{n}a_i$ 个士兵是必死无疑的

每场战斗有 $b_i$ 个士兵参加,这些士兵不一定都死

所以我们考虑如何把这些士兵压榨出更多的剩余价值

那么显然地可以考虑到将据点按照攻打之后能活下的人排序,这样可以让参加下一场战斗的士兵最多

然后贪心即可,复杂度 $\Theta(Tn\log n)$

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#define int long long
#define WR WinterRain
using namespace std;
const int WR=1001000;
struct City{
    int a,b;
}city[WR];
int n,ans;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-48;
        ch=getchar();
    }
    return s*w;
}
bool cmp(City x,City y){
    return x.b-x.a>y.b-y.a;
}
signed main(){
    //freopen("army.in","r",stdin);
    //freopen("army.out","w",stdout);
    int t=read();
    while(t--){
        n=read();
        for(int i=1;i<=n;i++) city[i].a=read(),city[i].b=read();
        sort(city+1,city+1+n,cmp);
        int tmp;
        ans=tmp=0;
        for(int i=1;i<=n;i++){
            ans+=max(city[i].b-tmp,(long long)0);
            tmp=max(tmp,city[i].b);
            tmp-=city[i].a;
        }
        printf("%lld\n",ans);
    }
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}
View Code

 

B. 虚弱

人类迷惑行为大赏

大家可以注意到这个 $\operatorname{SB}$ 开了个 $eps$ 然后类型是 $\operatorname{int}$

然后呢?一整道题分挂没了

愉悦

言归正传,不妨设 $s$ 为 $a$ 的前缀和数组

题意可以化简成取一个实数 $x$ 使得 $\forall 0\leqslant j \leqslant i\leqslant n $ ,有 $\left\vert s[i]-s[j]-(i-j)x \right\vert \leqslant ans$ ,求 $ans$ 最小值

原式即为 $\left\vert (s[i]-ix)-(s[j]-jx) \right\vert \leqslant ans$ ,也就是说我们要求 $\max\limits_{i=0}^{n}{s_i-ix}-\min\limits_{i=0}^{n}{s_i-ix}$ 最小

这是一个关于 $x$ 的函数,显然是有一个单峰的,所以考虑二分 / 三分,每次求一个最大子段和

不妨设 $mid=\dfrac{l+r}{2}$ ,$f(i)$ 表示 $x=i$ 时的最大子段和

可以设 $midl=mid-(eps\times 0.1)$ ,$midr=mid+(eps\times 0.1)$

那么考虑求出 $f(midl)$ 和 $f(midr)$ 后进行比较,如果 $f(midl)<f(midr)$ 那么用 $midr$ 更新 $r$ ,否则用 $midl$ 更新 $l$ 

注意原题精度卡到了丧心病狂的地步,需要把精度开到 $10^{-12}$ ,类型开为 $long$ $double$ 才可能过

 

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#define int long long
#define double long double
#define WR WinterRain
using namespace std;
const int WR=1001000;
const double eps=1e-12;
int n;
double sum,a[WR];
int modu[WR];
double ans1,ans2;
int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch>'9'||ch<'0'){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=(s<<3)+(s<<1)+ch-48;
        ch=getchar();
    }
    return s*w;
}
double check(double x){
    for(int i=1;i<=n;i++) a[i]=(double)modu[i]-x;
    double tmp1=0.0,tmp2=0.0;
    ans1=0.0,ans2=0.0;
    for(int i=1;i<=n;i++){
        if(tmp1>eps) tmp1+=a[i];
        else tmp1=a[i];
        if(tmp1>ans1) ans1=tmp1;
        a[i]=-a[i];
    }
    for(int i=1;i<=n;i++){
        if(tmp2>eps) tmp2+=a[i];
        else tmp2=a[i];
        if(tmp2>ans2) ans2=tmp2;
    }
    return max(ans1,ans2);
}
signed main(){
    freopen("weakness2.in","r",stdin);
    freopen("weakness.out","w",stdout);
    n=read();
    double l=(double)WR,r=-(double)WR;
    for(int i=1;i<=n;i++){
        modu[i]=read();
        l=min(l,(double)modu[i]);
        r=max(r,(double)modu[i]);
    }
    while((r-l)>eps){
        double midl=(l+r)/2-eps*0.1,midr=(l+r)/2+eps*0.1;
        if(check(midl)<check(midr)){
            r=midr;
        }else{
            l=midl;
        }
    }
    printf("%.6Lf",check(l));
    //fclose(stdin);
    //fclose(stdout);
    return 0;
}
View Code

 

官方的题解是用的单调栈,这里借用了一下证明

官方题解

好的

标签:ch,NOIP,22,int,double,eps,联训,WR,include
来源: https://www.cnblogs.com/WintersRain/p/16507958.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有