Lightoj1084【DP啊DP】

题意:

给你n个人的位置,每个人最多移动k个单位,然后在某点>=3人可以抱团,问你这n个人最少抱团数,只要有一个n不能抱团输出-1;

思路:

感觉又是超级超级狗血。。。。

剪不断,理还乱。。。

现对人的位置拍个序

一开始想的是贪心,纯粹因为n1e5...,然后思路是对于每个位置搞一下,能延伸的最远距离,然后自然而然GG,位置没有办法。

后面去想对于每个人,向两边延伸最长距离,然后状态转移GG= =、

然后想前i个人,后面副参考窝大哥的博客,他是以第i个人为左边界,然后右边界的位置就是pos[i]+2*k,然后在数组里面找一下这个位置的人的位置,两个人区间人数>=3,然后取最小就好了;

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int>PII;
const double eps=1e-5;
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;

const int N=1e5+10;
int f[N],a[N];
int n,k;

int dfs(int i)
{
    if(f[i]!=-1)
        return f[i];
    if(i==n)
        return f[i]=0;
    int pos=upper_bound(a,a+n,a[i]+k)-a;
    f[i]=INF;
    for(int j=pos;j-i>=3;j--)
        f[i]=min(f[i],1+dfs(j));
    return f[i];
}

int main()
{
    int T,cas=1;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
            scanf("%d",&a[i]);
        k*=2;
        sort(a,a+n);
        memset(f,-1,sizeof(f));
        dfs(0);
        if(f[0]<=0||f[0]==INF)
            f[0]=-1;
        printf("Case %d: %d
",cas++,f[0]);
    }
    return 0;
}