BJ 集训测试7 Mythological VII

本文介绍了一种在一维数组上实现的贪心匹配算法,该算法通过预处理前缀和来简化区间求和的问题,并利用贪心策略进行匹配扩展。文章详细描述了算法的具体实现过程,并附带完整的C++代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/archives/2751
一列数 给定起始位置两个人一个人只能向左移动 一个人只能向右移动 然后要求满足(px,py]这个区间的所有数和都<=0 大概n^2dp 写一下水30

但是正解贪心 考场上很多巨佬乱搞ac 我还是没有吃一堑长一智 在thuwc吃的亏 现在也没记住 既然会写namespace了也不写完部分分之后暴力贪心瞎搞一下 后来还剩20分钟觉得t1暴力可搞因为太着急了 就写错了两个变量白丢20分

这题贪心做首先 预处理前缀和 可以将题目的限制条件变成sum[i]-sum[j]>=0

一开始贪心匹配 根据这个式子暴力扩展即可

然后就需要根据之前预处理的前缀最大值最小值 还有后缀最大值最小值来处理了

if (mx1[x-1]<mx2[y+1]&&mn1[x-1]<mn2[y+1]) {puts("No");ok=1;break;}

这句话神坑 结束第一部分扩展之后第二部分的扩展注意这句话得加上 因为当且仅当满足这个条件时我无法再继续扩展了 否则还是有可能贪心继续扩展

#include<cstdio>
#include<algorithm>
#define ll long long
#define rg register
#define N 110000
#define inf 1LL<<60
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if (T==S) return EOF;}
    return *S++;
}
inline ll read(){
    ll x=0,f=1;char ch=gc();
    while(ch<'0'||ch>'9'){if (ch=='-')f=-1;ch=gc();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=gc();
    return x*f;
}
ll a[N],mn1[N],mx1[N],mn2[N],mx2[N];int n,k;
int main(){
    freopen("t3.in","r",stdin);
    int T=read();mn1[0]=inf;mx1[0]=-inf;
    while(T--){
        n=read();k=read();for (rg int i=1;i<=n;++i) a[i]=a[i-1]+read();mn2[n+1]=inf;mx2[n+1]=-inf;
        for (rg int i=1;i<=n;++i) mn1[i]=min(mn1[i-1],a[i]),mx1[i]=max(mx1[i-1],a[i]);
        for (rg int i=n;i;--i) mn2[i]=min(mn2[i+1],a[i]),mx2[i]=max(mx2[i+1],a[i]);
        int x=k,y=k;bool flag=1,ok=0;
        while(flag){
            flag=0;
            for (rg int i=x-1;i&&a[i]>=a[y];--i) if (a[i]>=a[x]) {flag=1;x=i;break;}
            for (rg int i=y+1;i<=n&&a[i]<=a[x];++i) if (a[i]<=a[y]) {flag=1;y=i;break;} 
        }if (a[y]>mn1[x]||a[x]<mx2[y]) {puts("No");continue;}
        while(x!=1||y!=n){
            if (x==1) {while(y<n&&a[y+1]<=a[x]) ++y;break;}
            if (y==n) {while(x>1&&a[x-1]>=a[y]) --x;break;}
            if (x==1&&y==n) {puts("Yes");ok=1;break;}
            if (x==1||y==n) {
                if (x==1)++y;else if (y==n) --x;if (a[x]<a[y]) {puts("No");ok=1;break;}
            }else{
                if (mx1[x-1]<mx2[y+1]&&mn1[x-1]<mn2[y+1]) {puts("No");ok=1;break;}
                if (mx1[x-1]>=mx2[y+1]) --x;else ++y;   
            }
        }if (!ok) x==1&&y==n?puts("Yes"):puts("No");
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值