羅区[P3957]石蹴り

タイトル効果:Nポイントと軸を考えると、現在の位置0から始めて、少し右を指して、唯一の初期の距離dを取ることができ、そして数直線上の任意の位置で停止することができ、この時間は、ポイントが右になりますそして、。それぞれが範囲[MAX(1、DX)、D + X]から行くことができるようにXは現在、支払うことを許可されています。それは、少なくともどのくらいの権利を通って、少なくともkにおけるポイントを作るために支払うことが必要です。

溶液:問題の範囲の既知のデータによれば、(1)時間要する状態での状態と一次元O転送。
Xは、右のポイントと、少なくともKを満たすために価格を支払うことを発見された場合には、一定の条件を満たすために多くの費用を支払います。したがって、点Quanshi点が通過するかどうか、コスト、DP、最適解に係る決意の各半分を、バイナリ回答を検討し、条件を満たしています。
転送をDPすると、転送・ノートでは、途中、ほとんど連続値であるので、単調なキューを考えます。まず、新しい状態が現在の状態、チームに新しい状態に転送することができるかを決定;第二に、キューをポップアップ表示されますチーム、で合法的なされていない状態を判断するために、そして最終的に合法的な転送が可能。

コードは以下の通りです

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e5+10;
typedef long long LL;

LL f[maxn];
int n,d,k,pos[maxn],s[maxn];

bool check(int g){
    static int q[maxn];
    int l=1,r=0,now=0;
    for(int i=1;i<=n;i++)f[i]=-1e15;
    for(int i=1;i<=n;i++){
        while(now<i&&pos[i]-pos[now]>=d-g){
            while(l<=r&&f[now]>=f[q[r]])--r;
            q[++r]=now++;
        }
        while(l<=r&&pos[i]-pos[q[l]]>d+g)++l;
        if(l<=r)f[i]=f[q[l]]+s[i];
    }
    for(int i=1;i<=n;i++)if(f[i]>=k)return 1;
    return 0;
}

int main(){
    scanf("%d%d%d",&n,&d,&k);
    LL sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d%d",&pos[i],&s[i]);
        if(s[i]>=0)sum+=s[i];
    }
    if(sum<k)return puts("-1"),0;
    
    int l=0,r=1e9;
    while(l<r){
        int mid=l+r>>1;
        if(check(mid))r=mid;
        else l=mid+1;
    }
    printf("%d\n",l);
    
    return 0;
} 

おすすめ

転載: www.cnblogs.com/wzj-xhjbk/p/11318139.html