codeforce 985E dp+BIT

15 篇文章 0 订阅
3 篇文章 0 订阅

题目链接:点击打开链接

思维很重要,首先要把这个问题抽象成模型。即能否用若干个盒子装下n个物品,每个盒子里的物品价值范围为ai,aj和ai到aj区间内的所有物品。

用dp【i】表示从i到n个物品能否按规则装下,是为1,否为0;

先将从小到大数组排序

考量一个dp【i】时只需考量dp【i+k+1】,dp【i+k+2】。。。dp【x】(a【x】为upper_bound(a【i】+d+1))

其中若有一个dp值为1,那么dp【i】就为1。

从后向前dp,最后的结果取决于dp【1】;

判断时因为i+d可能大于n,所以细节处理至关重要,注意特判k==1的情况

#include<iostream>
#include<cstdio>
#include<vector>
#include<set>
#include<map>
#include<string.h>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#define LL long long
#define mod 1000000007
#define inf 0x3f3f3f3f
#define sqr(a) (a)*(a)
#define For(i,m,n) for(int i=m;i<=n;i++)
#define Dor(i,n,m) for(int i=n;i>=m;i--)
#define lan(a,b) memset(a,b,sizeof(a))
#define maxn 500010

using namespace std;
LL shu[maxn];
LL a[maxn];
int dp[maxn];
int n,k,d;

int lowbit(int i)
{
    return i&(-i);
}

int query(int i)
{
    int ans=0;
    while(i)
    {
        ans+=shu[i];
        i-=lowbit(i);
    }
    return ans;
}

void update(int p,int i)
{
    while(i<=n )
    {
        shu[i]+=p;
        i+=lowbit(i);
    }
}

int main()
{
    while(~scanf("%d%d%d",&n,&k,&d))
    {
        lan(a,0);
        lan(shu,0);
        lan(dp,0);
        For(i,1,n)
        scanf("%lld",&a[i]);
        if(k==1)
        {
            printf("YES\n");
            continue;
        }
        sort(a+1,a+1+n);
        dp[n]=0;
        update(0,n);
        for(int i=n-1;i>=1;i--)
        {
            int t1=i+k-1;
            int t2=upper_bound(a+1,a+1+n,a[i]+d)-a-1;
            //cout << i << " " << t1 << " " << t2 << endl;
            if(t1>t2)
            {
                dp[i]=0;
                update(0,i);
                continue;
            }
            if(t2==n)
            {
                dp[i]=1;
                update(1,i);
       // cout << dp[i] << endl;
                continue;
            }
           // printf("query=%d\n",query(t2+1)-query(t1));
            if(query(t2+1)-query(t1))
            {
                dp[i]=1;
                update(1,i);
            }
            else
            {
                dp[i]=0;
                update(0,i);
            }
            //cout << dp[i] << endl;
        }
        if(dp[1])
            printf("YES\n");
        else
            printf("NO\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值