题意:给n个数,并给一个区间[a,b],第一次选的数要在这个区间内,然后每次选n个数中的某个数,使得这个数减去对手所选的数得到的差值在[a,b]区间内。
要求第一个选手所选的数的和减去第二个人所选的数的和的最大差值。
a>0,很明显每次选的数只可能比上次所选的数大,所以把这n个数进行排序。
dp[i]表示选择i位置的数所能得到的最大差值。
小盆友1必取第i位置上的数,这是我们的定义,小盆友2很聪明,他就不想让小盆友1取得最大值,于是,小盆友2选择可取的j中dp[j]最大的一个,这样dp[i]就小盆友1从这里取的差值就小了。
既:dp[i]=a[i]-max{dp[j]}。
ccy代码:
#include<iostream>
using namespace std;
const int maxn=10010;
int a[maxn];
int dp[maxn];
int Case,n,A,B;
void qsort(int l,int r)
{
int i=l,j=r,mid=a[(l+r)>>1];
while (i<j)
{
while (a[i]<mid) i++;
while (mid<a[j]) j--;
if (i<=j)
{
swap(a[i],a[j]);
i++; j--;
}
}
if (l<j) qsort(l,j);
if (i<r) qsort(i,r);
}
int DP()
{
for (int i=n;i>=1;i--)//从后往前坐
{
int MAX=INT_MIN;//注意是INT_MIN,因为数字中有负数
bool flag=false;//标志是否有可取的j
for (int j=i+1;j<=n;j++)
{
int cz=a[j]-a[i];//差值
if (B<cz) break;//因为已经排了序,所以可以提前退出
if (A<=cz && cz<=B)
{
flag=true;
MAX=max(MAX,dp[j]);//小盆友2很聪明,他要让被减数尽可能的大,这样,差值就尽可能的小,他就是不要如小盆友1的意
}
}
if (!flag) MAX=0;//如果flag==false,说明小盆友2没有办法再取数,游戏结束,后面无差值,所以MAX=0
dp[i]=a[i]-MAX;
}
bool flag=false;
int MAX=INT_MIN;
for (int i=1;i<=n;i++)//选小盆友1可以取的第一个数中dp最大那个数
{
if (A<=a[i] && a[i]<=B)
{
flag=true;
MAX=max(MAX,dp[i]);
}
if (B<a[i]) break;
}
if (!flag) MAX=0;//如果flag==false,说明连小盆友1都没法下手选,最后结果差值当然为0
return MAX;
}
int main()
{
scanf("%d",&Case);
while (Case>0)
{
Case--;
scanf("%d%d%d",&n,&A,&B);
for (int i=1;i<=n;i++)
scanf("%d",&a[i]);
qsort(1,n);//排序
printf("%d\n",DP());
}
return 0;
}