zoukankan      html  css  js  c++  java
  • [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
    ",ans);
    57     out(n,num);
    58 }
  • 相关阅读:
    Java 实现 蓝桥杯 生兔子问题
    Java实现 蓝桥杯 基因牛的繁殖
    Java实现 蓝桥杯 基因牛的繁殖
    Java实现 蓝桥杯 基因牛的繁殖
    Java实现 LeetCode 33 搜索旋转排序数组
    Java实现 LeetCode 33 搜索旋转排序数组
    Java实现 LeetCode 33 搜索旋转排序数组
    深入探究VC —— 资源编译器rc.exe(3)
    深入探究VC —— 编译器cl.exe(2)
    深入探究VC —— 编译器cl.exe(1)
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9296436.html
Copyright © 2011-2022 走看看