ARC 072

C
相邻前缀不相同就是没有0
只有+-+-+-和-+-+-+两种情况,枚举
每个位置加减会改变后面所有前缀和,所以这个位置只要修改到符合符号就行了

D
(打表)发现|X-Y|<=1时先手必败

E
记从1开始走到i时刻前距离终点di,发现witch就是把di+1变成0~di的一个数
维护一个最大的now表示i这个时刻后,距离终点0~now都一定能到达终点,i=n时now=0,然后从n往前递推,
当ai<=now+1或ai>now+1且ai-(now+1)<=now时now+=ai,
否则now不变,
di>now时witch能让他变成now+1使其不能到达终点

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 610000;

int n,Q,D,ed;
int a[maxn],d[maxn];

int ok[maxn];

int main()
{
    scanf("%d%d",&n,&D);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);

    int tmp=D;
    for(int i=1;i<=n;i++) if(a[i]<tmp*2) 
    {
        d[i]=tmp;
        tmp=a[i]>tmp?a[i]-tmp:tmp-a[i];
        if(!tmp) { ed=i; break; }
    }
    if(tmp) for(int i=1;i<=n;i++) ok[i]=1;
    else
    {
        int now=0;
        for(int i=n;i>=1;i--)
        {
            int x=a[i+1];
            if((x-(now+1)<=now)) now+=x;
            if(ed<i) { ok[i]=0; continue; }
            if(d[i]>now) ok[i]=1;
        }
    }
    scanf("%d",&Q);
    while(Q--)
    {
        int x; scanf("%d",&x);
        puts(ok[x]?"YES":"NO");
    }

    return 0;
}

F
用一个二元组(x,y)表示水量有x升,x*temperature=y,的状态,
维护第i天水量为j的最大温度f[i][j],将f[i][j]表示在二维平面上,j为横坐标,f[i][j]为纵坐标,发现是一些折线,比如f[1][L]就是一条连接(0,0)和(v,vt)的线段。
每一天,会在头部连上一条线段,可以发现维护一个上凸的凸包一定保证每个j的f[i][j]最优

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long 
using namespace std;

const int maxn = 510000;

int n,L;
struct node{double x,y;}a[maxn<<1]; int head,tail;

double multi(node x,node y,node z)
{
    x.x-=z.x; x.y-=z.y;
    y.x-=z.x; y.y-=z.y;
    return x.x*y.y-x.y*y.x;
}

int main()
{
    scanf("%d%d",&n,&L); n--;
    a[head=maxn]=(node){0.0,0.0};
    ll x,y;
    tail=head+1; scanf("%lld%lld",&y,&x);
    printf("%lf\n",(double)y); a[tail].y=(double)x*y; a[tail].x=x;

    for(int i=1;i<=n;i++)
    {
        scanf("%lld%lld",&y,&x); y*=x;
        node now=(node){a[head].x-(double)x,a[head].y-(double)y};
        while(head+1<=tail&&a[tail-1].x-now.x>=L) tail--;
        if(head!=tail)
        {
            double pt=(a[tail].y-a[tail-1].y)/(a[tail].x-a[tail-1].x);
            if(a[tail].x-now.x>L)
            {
                a[tail].y=a[tail-1].y+(L-(a[tail-1].x-now.x))*pt;
                a[tail].x=now.x+L;
            }
        }
        while(head+1<=tail&&multi(a[head],a[head+1],now)>=0) head++;
        a[--head]=now;
        double kk=a[tail].y-now.y;
        printf("%lf\n",kk/(double)L);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值