luoguT30208 太极剑(贪心)

版权声明:转载附上原文地址即可~欢迎各位神犇来虐~ https://blog.csdn.net/Icefox_zhx/article/details/80693609

某题的弱化版…
我觉得是挺神的,考场上只想出了线性规划然而不会写了x
首先我们有一个结论:我们可以把切割线分配到点上去,这样只要一条线段两边的点的权值和分别大于等于线段权值即可。
然后所有点的权值和+1/2就是答案下界,并可以证明这个下界是可以达到的。
因此问题转化成分配点权,使得总权值最小。
然后此题权值都是1,每两个同色点之间都要有一个切割点,可以贪心地让每两个相邻的切割点之间没有同色点来实现
直接枚举一个起点,拆环成链,这样是O(n2)的,但是我们注意到相邻最近的点对之间必有一个切割点,设他们之间距离为d,那么我们只需枚举这d个点即可,每一次贪心的复杂度可以做到O(n/d),需要预处理一下每个点往后延伸的最远距离。总的复杂度就是O(n)了。

菜到不想说话qaq

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 400010
inline char gc(){
    static char buf[1<<16],*S,*T;
    if(T==S){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x*f;
}
int n,nxt[N<<1],ans=inf,opp[N<<1];
inline int calc(int x){
    int res=0,ed=n+x-1;
    while(1){
        if(x>ed) break;++res;x=nxt[x];
    }return res+1>>1;
}
int main(){
//  freopen("a.in","r",stdin);
    n=read()*2;int sx=1,sy=n;
    for(int i=1;i<=n/2;++i){
        int x=read(),y=read();if(x>y) swap(x,y);if(y-x<sy-sx) sx=x,sy=y;
        opp[x]=y;opp[y]=n+x;opp[n+x]=n+y;opp[n+y]=2*n+1;
    }nxt[2*n]=2*n+1;
    for(int i=n*2-1;i;--i) nxt[i]=min(opp[i],nxt[i+1]);
    for(int i=sx+1;i<=sy;++i) ans=min(ans,calc(i));
    printf("%d\n",ans);
    return 0;
}
阅读更多
换一批

没有更多推荐了,返回首页