码迷,mamicode.com
首页 > 其他好文 > 详细

JOISC2017C 手持ち花火

时间:2020-02-21 18:01:54      阅读:75      评论:0      收藏:0      [点我收藏+]

标签:tps   include   有一个   ref   扩展   inline   cpp   long   ace   

Link
首先二分答案\(v\)
考虑这样一个结论:最优解一定是\(K\)不动,其它人往\(K\)这里跑,跑到了之后先不点燃,等\(K\)的位置上每有一个人的火熄灭就点燃下一个。
那么如果我们能够点燃区间\([L,R]\)的所有烟火,就需要存在一个扩展路径上的所有\(l,r\)满足:
\[x_l+vT(r-l)\ge x_r-vT(r-l)\]
移项得
\[x_l-2vTl\ge x_r-2vTr\]
\(a_i=x_i-2vTi\),上式就是\(a_l\ge a_r\)
因此,存在一种点燃方案,等价于存在\(p_1\cdots p_n,P_1\cdots P_n\),使得\(p_1=P_1=k,p_n=1,P_n=n\),随着\(i\)递增每次\(p_i\)减一或者\(P_i\)加一,并且保证\(a_{p_i}\ge a_{P_i}\)
也就是存在一个扩展路径使得路径上的每对\(l,r\)满足\(a_l\ge a_r\)
假如我们现在有区间\([l,r]\),我们要对它扩展。
考虑如何扩展\(l\),若存在\(i\),使得
1:\(a_i\ge a_l\)
2:\(\forall j\in[i,l],a_j\ge a_r\)
条件2显然是必须满足的,条件一是为了使接下来\(r\)一定更远。
那么我们就可以进行一次把左端点扩展到\(i\)的扩展。
每次扩展时找到最右边的能扩展的\(i\)即可。
扩展\(r\)也是同样的操作。
如果某次我们\(l,r\)都没有扩展,并且都是因为条件2不满足,那么这个\(v\)一定不合法。
如果是因为条件1不满足,我们无能为力。
接下来考虑如何解决这个问题。
我们求出\(a_1\sim a_{K-1}\)中最大值\(a_{pl}\)\(a_{K+1}\sim a_n\)中的最小值\(pr\)
显然如果我们能够扩展到\([pl,pr]\),那么接下来1条件一定不满足,并且说明过程中2条件都满足,这一部分是合法的。
我们再考虑将左端点\(l\)设为\(1\),右端点\(r\)设为\(n\),向内扩展。扩展过程就是上面的反过来。
如果我们还能扩展到\([pl,pr]\),那么说明过程中2条件都满足,也就是这个\(v\)合法。
我们要计算的有\(vTi\),这个东西显然可能爆long long。
我们注意到,当\(vT\ge10^9\)时,一定可以点燃所有烟花,所以一开始把二分的右端点设为\(\frac{10^9}{T}+1\)即可。

#include<bits/stdc++.h>
#define LL long long
#define mid ((l+r)>>1)
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],*iS,*iT;
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    int read(){int x=0;char ch=Get();while(ch>57||ch<48)ch=Get();while(ch>=48&&ch<=57)x=x*10+(ch^48),ch=Get();return x;}
}
using namespace IO;
const int N=100007,inf=1e9;
int n,K,T,x[N];
LL a[N];
int check(int v)
{
    int i,l,r,L,R,ql,qr,f;
    for(i=1;i<=n;++i) a[i]=1ll*x[i]-2ll*T*v*i;
    if(a[1]<a[n]) return 0;
    for(ql=qr=K,i=K-1;i;--i) if(a[i]>=a[ql]) ql=i;
    for(i=K+1;i<=n;++i) if(a[i]<=a[qr]) qr=i;
    for(l=r=K;l^ql||r^qr;)
    {
    f=0,L=l,R=r;
        for(;L>ql&&a[L-1]>=a[r];) if(a[--L]>=a[l]) break;
        if(L<l&&a[L]>=a[l]) f=1,l=L;
        for(;R<qr&&a[R+1]<=a[l];) if(a[++R]<=a[r]) break;
    if(R>r&&a[R]<=a[r]) f=1,r=R;
        if(!f) return 0;
    }
    for(l=1,r=n;l^ql||r^qr;)
    {
    f=0,L=l,R=r;
        for(;L<ql&&a[L+1]>=a[r];) if(a[++L]>=a[l]) break;
        if(L>l&&a[L]>=a[l]) f=1,l=L;
    for(;R>qr&&a[R-1]<=a[l];) if(a[--R]<=a[r]) break;
    if(R<r&&a[R]<=a[r]) f=1,r=R;
        if(!f) return 0;
    }
    return 1;
}
int main()
{
    n=read(),K=read(),T=read();int i,l=0,r=inf/T+1,ans;
    for(i=1;i<=n;++i) x[i]=read();
    while(l<=r) check(mid)? ans=mid,r=mid-1:l=mid+1;
    printf("%d\n", ans);
}

JOISC2017C 手持ち花火

标签:tps   include   有一个   ref   扩展   inline   cpp   long   ace   

原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12342182.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!