假定给出一个包含N个整数的数组A,包含N+1个整数的数组ID,与整数R。其中ID数组中的整数均在区间[1,N-1]中。
用下面的算法对A进行Warshall-Turing-Fourier变换(WTF):
sum = 0
for i = 1 to N
index = min{ ID[i], ID[i+1] }
sum = sum + A[index]
将数组A往右循环移动R位
将数组A内所有的数取相反数
for i = 1 to N
index = max{ ID[i], ID[i+1] }
index = index + 1
sum = sum + A[index]
将数组A往右循环移动R位
给出数组A以及整数R,但没有给出数组ID。在对数组A进行了WTF算法后,变量sum的可能出现的最大值数多少?
第一行包含两个整数N与R。
第二行包含N个整数,代表A[1]到A[N]的值。
第一行输出变量sum可能出现的最大值。
第二行输出此时的ID数组,包含N+1个整数。必须满足ID数组中每一个数均在区间[1,N-1]中。若有多个满足的ID数组,输出任意一组。
如果第一行是正确的(不管有没有输出第二行),你能得到该测试点50%的得分。
输入1:
5 3
1 -1 1 -1 1
输入2:
6 5
2 5 4 1 3 5
输出1:
10
1 1 1 2 2 3
输出2:
16
3 2 1 1 5 4 1
对于20%的数据,N<=7。
对于60%的数据,N<=300。
对于100%的数据,2<=N<=3000, 1<=R
可以发现一个ID只和上一个ID与下一个ID有关,考虑DP。
设f[i][j]表示第i个ID填j最大的sum。
当k>j
f[i][j]=maxf[i−1][k]+a[min(j,k)]−a[max(j,k)+1]
当k<=j
f[i][j]=maxf[i−1][k]+a[k]−a[j+1]
注意一下a值变换
还有要用g[i][j] 记录前驱
代码
#include
#include
#include
using namespace std;
const int inf=0x3f3f3f3f,maxn=3077;
int n,r,a[maxn],f[maxn][maxn],g[maxn][maxn],ass,t;
void print(int x,int y)
{
if(x!=0) print(x-1,g[x][y]);
printf("%d ",y+1);
}
int main()
{
memset(f,200,sizeof(f));
memset(f[0],0,sizeof(f[0]));
scanf("%d%d",&n,&r);
for(int i=0; i"%d",&a[i]);
for(int i=1; i<=n; i++)
{
ass=-inf;
for(int j=0; j1; j++)
{
if(f[i-1][j]+a[((j-(i-1)*r)%n+n)%n]>ass)
{
ass=f[i-1][j]+a[((j-(i-1)*r)%n+n)%n];
t=j;
}
if(ass-a[((j+1-(i-1)*r)%n+n)%n]>f[i][j])
{
f[i][j]=ass-a[((j+1-(i-1)*r)%n+n)%n];
g[i][j]=t;
}
}
ass=-inf;
for(int j=n-2; j>=0; j--)
{
if(f[i-1][j]-a[((j+1-(i-1)*r)%n+n)%n]>ass)
{
ass=f[i-1][j]-a[((j+1-(i-1)*r)%n+n)%n];
t=j;
}
if(ass+a[((j-(i-1)*r)%n+n)%n]>f[i][j])
{
f[i][j]=ass+a[((j-(i-1)*r)%n+n)%n];
g[i][j]=t;
}
}
}
ass=-inf;
for(int j=0; j1; j++) if(f[n][j]>ass)
{
ass=f[n][j];
t=j;
}
printf("%d\n",ass);
print(n,t);
}