[dp] Jzoj P4262 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<N, -10000<=A[i]<=10000。

题解

  • 可以发现,ID[i]对答案的贡献只有ID[i+1],可以考虑dp
  • 设f[i][j]为前i个位置,第i个位置选j的最大sum值
  • 显然得出f[i][j]=max(f[i-1][k]+a[min(j,k)]-a[min(j,k+1])
  • 考虑一下如果得出移动后r的位置
  • x=((x-(i-1)*r)%n+n)%n
  • 然后再定义一个g[i][j]统计f[i][j]是选了那个数转换来的
  • 考虑两种情况k <= j,这时f[i][j]=max(f[i-1][k]+a[k]-a[j+1],f[i][j])
  • 如果k > j,这时f[i][j]=max(f[i-1][k]+a[j]-a[k+1],f[i][j])
    那么这样O(N^3),感觉时间有点虚
    考虑一下如果弄掉一个N
    我们可以正着跑一遍,再反着跑一遍,再判断是否合法,合法求最大值,记录g[i][j]

代码

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int inf=2147483647;
 6 int n,r,a[3010],f[3010][3010],g[3010][3010];
 7 void out(int x,int y)
 8 {
 9     if (x!=0) out(x-1,g[x][y]);
10     printf("%d ",y+1);
11 }
12 int main()
13 {
14     memset(f,200,sizeof(f));
15     memset(f[0],0,sizeof(f[0]));
16     scanf("%d%d",&n,&r);
17     for (int i=0;i<=n-1;i++) scanf("%d",&a[i]);
18     for (int i=1;i<=n;i++)
19     {
20         int ans=-inf,num;
21         for (int j=0;j<=n-2;j++)
22         {
23             if (f[i-1][j]+a[((j-(i-1)*r)%n+n)%n]>ans)
24             {
25                 ans=f[i-1][j]+a[((j-(i-1)*r)%n+n)%n];
26                 num=j;
27             }
28             if (ans-a[((j+1-(i-1)*r)%n+n)%n]>f[i][j])
29             {
30                 f[i][j]=ans-a[((j+1-(i-1)*r)%n+n)%n];
31                 g[i][j]=num;
32             }
33         }
34         ans=-inf;
35         for (int j=n-2;j>=0;j--)
36         {
37             if (f[i-1][j]-a[((j+1-(i-1)*r)%n+n)%n]>ans)
38             {
39                 ans=f[i-1][j]-a[((j+1-(i-1)*r)%n+n)%n];
40                 num=j;
41             }
42             if (ans+a[((j-(i-1)*r)%n+n)%n]>f[i][j])
43             {
44                 f[i][j]=ans+a[((j-(i-1)*r)%n+n)%n];
45                 g[i][j]=num;
46             }    
47         }
48     }
49     int ans=-inf,num;
50     for (int j=0;j<=n-2;j++)
51         if (f[n][j]>ans)
52         {
53             ans=f[n][j];
54             num=j;
55         }
56     printf("%d\n",ans);
57     out(n,num);
58 }

猜你喜欢

转载自www.cnblogs.com/Comfortable/p/9296436.html
今日推荐