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 }
  • 相关阅读:
    Linux内核分析——第四章 进程调度
    Linux内核分析——可执行程序的装载
    Linux内核分析——第七章 链接
    Linux内核分析——第三章 进程管理
    Linux内核分析——进程的描述和进程的创建
    Linux内核分析——第十八章 调试
    Linux内核分析——第五章 系统调用
    20145201李子璇 《网络对抗》 Web安全基础实践
    20145201李子璇 《网络对抗》 Web基础
    20145201 李子璇 《网络对抗》网络欺诈技术防范
  • 原文地址:https://www.cnblogs.com/Comfortable/p/9296436.html
Copyright © 2011-2022 走看看