【JZOJ B组】【NOIP2015模拟10.22】WTF交换

Description

假定给出一个包含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的可能出现的最大值数多少?

Input

第一行包含两个整数N与R。
第二行包含N个整数,代表A[1]到A[N]的值。

Output

第一行输出变量sum可能出现的最大值。
第二行输出此时的ID数组,包含N+1个整数。必须满足ID数组中每一个数均在区间[1,N-1]中。若有多个满足的ID数组,输出任意一组。
如果第一行是正确的(不管有没有输出第二行),你能得到该测试点50%的得分。

Sample Input

输入1:
5 3
1 -1 1 -1 1
输入2:
6 5
2 5 4 1 3 5

Sample Output

输出1:
10
1 1 1 2 2 3
输出2:
16
3 2 1 1 5 4 1

Data Constraint

对于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);
}

你可能感兴趣的:(题解,dp)