Description
给定一个长度为 n 的非负整数序列 a_1,a_2,...a_n 。你可以使用一种操作:选择在序列中连续的两个正整数,
并使它们分别减一。当你不能继续操作时游戏结束,而你的得分等于你使用的操作次数。你的任务是计算可能的最小
得分和最大得分。
Input
第一行包含一个正整数 T ,表示有 T 组数据,满足 T ≤ 200 。
接下来依次给出每组测试数据。对于每组测试数据:
第一行包含一个正整数 n ,满足 1 ≤ n ≤ 10^5 。
第二行包含 n 个非负整数,表示 a_1,a_2,...a_n ,满足 Σa_i ≤ 10^6 。
约 5 组数据满足 n ≥ 10^3 或 Σa_i ≥ 10^4 。
Output
对于每组测试数据
输出一行两个非负整数,用一个空格隔开,前者表示可能的最小得分,后者表示可能的最大得分。
Sample Input
2
4
1 2 1 3
5
1 2 1 1 3
4
1 2 1 3
5
1 2 1 1 3
Sample Output
2 2
2 3
2 3
HINT
Source
DP果然还是不太行。。
f[i][j]表示第i个消成j的最大答案,前面一位必定消光而当前位可以有剩
F[i][j]表示第i个消成j的最大答案,当前位必定消光而前一位可以有剩
那么就有f[i][j]=max(f[i-1][a[i]-j],F[i-1][a[i]-j])+a[i]-j;
再令fx为f后缀和
F[i][j]=max(fx[i-1][a[i]-j],F[i-1][a[i]-j])+a[i]-j;
然后最小值设为g,G,与f,F同理
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<cstdlib>
#include<algorithm>
using namespace std;
int f[2][1000011],F[2][1000011];
int g[2][1000011],G[2][1000011];
int a[1000011];
int main()
{
// freopen("data.in","r",stdin);
// freopen("data.out","w",stdout);
int T;
scanf("%d",&T);
while(T>0)
{
T--;
int n;
scanf("%d",&n);
int i,j;
int lim=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
lim=max(lim,a[i]);
}
if(n==1)
{
printf("0 0\n");
continue;
}
for(j=0;j<=lim;j++)
{
f[0][j]=-1000000000;
F[0][j]=-1000000000;
g[0][j]=1000000000;
G[0][j]=1000000000;
f[1][j]=-1000000000;
F[1][j]=-1000000000;
g[1][j]=1000000000;
G[1][j]=1000000000;
}
int p=0,q=1;
int tmp=min(a[1],a[2]);
for(i=0;i<tmp;i++)
F[p][a[2]-i]=G[p][a[2]-i]=i;
f[p][a[2]-tmp]=tmp;
g[p][a[2]-tmp]=tmp;
for(i=3;i<=n;i++)
{
for(j=1;j<=a[i];j++)
{
f[q][j]=max(f[p][a[i]-j],F[p][a[i]-j])+a[i]-j;
g[q][j]=min(g[p][a[i]-j],G[p][a[i]-j])+a[i]-j;
}
for(j=a[i];j<=a[i-1];j++)
{
f[q][0]=max(f[q][0],f[p][j]+a[i]);
g[q][0]=min(g[q][0],g[p][j]+a[i]);
}
f[q][0]=max(f[q][0],F[p][a[i]]+a[i]);
g[q][0]=min(g[q][0],G[p][a[i]]+a[i]);
for(j=a[i-1]-1;j>=0;j--)
{
f[p][j]=max(f[p][j],f[p][j+1]);
g[p][j]=min(g[p][j],g[p][j+1]);
}
for(j=1;j<=a[i];j++)
{
F[q][j]=max(f[p][a[i]-j],F[p][a[i]-j])+a[i]-j;
G[q][j]=min(g[p][a[i]-j],G[p][a[i]-j])+a[i]-j;
}
for(j=0;j<=a[i-1];j++)
{
f[p][j]=-1000000000;
F[p][j]=-1000000000;
g[p][j]=1000000000;
G[p][j]=1000000000;
}
// for(j=0;j<=a[i];j++)
// printf("%d %d\n",g[q][j],G[q][j]);
// printf("\n");
p=1-p;
q=1-q;
}
int ansmax=-1000000000,ansmin=1000000000;
for(i=0;i<=a[n];i++)
{
ansmax=max(ansmax,f[p][i]);
ansmin=min(ansmin,g[p][i]);
}
printf("%d %d\n",ansmin,ansmax);
}
return 0;
}