JZOJ7月21日提高组T4 WTF交换【Special Judge】
题目
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。
题解
题意
有一种叫做WTF交换的东东(具体见题面)
现在给出数组
A
A
A,
R
R
R和
N
N
N,求最大的
s
u
m
sum
sum和满足最大
s
u
m
sum
sum的
I
D
ID
ID数组(任意一种即可)
分析
DP
设
f
[
i
]
[
j
]
f[i][j]
f[i][j]表示
I
D
ID
ID数组的第
i
i
i位选择
j
j
j的最大
s
u
m
sum
sum
第一行
最初转移
枚举一个
k
(
1
k(1
k(1~
n
−
1
)
n-1)
n−1)
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
k
]
+
a
[
g
e
t
(
m
i
n
(
j
,
k
)
)
]
−
a
[
g
e
t
(
m
a
x
(
j
,
k
)
+
1
)
]
)
f[i][j]=max(f[i-1][k]+a[get(min(j,k))]-a[get(max(j,k)+1)])
f[i][j]=max(f[i−1][k]+a[get(min(j,k))]−a[get(max(j,k)+1)])
何为
g
e
t
get
get?
若当前选择第
i
i
i个位置
那么之前肯定进行过
i
−
1
i-1
i−1次WTF操作
那么这个
j
(
k
)
j(k)
j(k)肯定会在数组内调换位置
g
e
t
get
get操作就是把一开始
j
(
k
)
j(k)
j(k)的位置找到
显而易见,这个转移是
O
(
n
3
)
O(n^3)
O(n3),只能拿60%的数据
优化
分类讨论:
当
k
≤
j
k≤j
k≤j时:
原方程变为:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
k
]
+
a
[
g
e
t
(
k
)
]
−
a
[
g
e
t
(
j
+
1
)
]
)
f[i][j]=max(f[i-1][k]+a[get(k)]-a[get(j+1)])
f[i][j]=max(f[i−1][k]+a[get(k)]−a[get(j+1)])
可以看出,
f
[
i
−
1
]
[
k
]
+
a
[
g
e
t
(
k
)
]
f[i-1][k]+a[get(k)]
f[i−1][k]+a[get(k)]是和
j
j
j没有关系的
既然要让答案最大,那么
f
[
i
−
1
]
[
k
]
+
a
[
g
e
t
(
k
)
]
f[i-1][k]+a[get(k)]
f[i−1][k]+a[get(k)]就应该最大
那么就可以设一个
s
s
s表示最大的
f
[
i
−
1
]
[
k
]
+
a
[
g
e
t
(
k
)
]
f[i-1][k]+a[get(k)]
f[i−1][k]+a[get(k)]
至于怎么满足
k
≤
j
k≤j
k≤j,就可以让
j
j
j顺着扫一遍,那么最大的
s
s
s所对应的
k
k
k肯定是在
1
1
1~
j
j
j里的
手动模拟过程:
- 新的 j j j进入
- 判断 f [ i − 1 ] [ j ] + a [ g e t ( j ) ] f[i-1][j]+a[get(j)] f[i−1][j]+a[get(j)]与 s s s的大小,更新 s s s
- 判断 s − a [ g e t ( j + 1 ) ] s-a[get(j+1)] s−a[get(j+1)]和 f [ i ] [ j ] f[i][j] f[i][j]的大小,更新 f [ i ] [ j ] f[i][j] f[i][j]
当
j
≤
k
j≤k
j≤k时:
原方程变为:
f
[
i
]
[
j
]
=
m
a
x
(
f
[
i
−
1
]
[
k
]
+
a
[
g
e
t
(
j
)
]
−
a
[
g
e
t
(
k
+
1
)
]
)
f[i][j]=max(f[i-1][k]+a[get(j)]-a[get(k+1)])
f[i][j]=max(f[i−1][k]+a[get(j)]−a[get(k+1)])
可以看出,
f
[
i
−
1
]
[
k
]
−
a
[
g
e
t
(
k
+
1
)
]
f[i-1][k]-a[get(k+1)]
f[i−1][k]−a[get(k+1)]是和
j
j
j没有关系的
既然要让答案最大,那么
f
[
i
−
1
]
[
k
]
−
a
[
g
e
t
(
k
+
1
)
]
f[i-1][k]-a[get(k+1)]
f[i−1][k]−a[get(k+1)]就应该最大
那么就可以设一个
s
s
s表示最大的
f
[
i
−
1
]
[
k
]
−
a
[
g
e
t
(
k
+
1
)
]
f[i-1][k]-a[get(k+1)]
f[i−1][k]−a[get(k+1)]
至于怎么满足
j
≤
k
j≤k
j≤k,就可以让
j
j
j倒着扫一遍,那么最大的
s
s
s所对应的
k
k
k肯定是在
j
j
j~
n
−
1
n-1
n−1里的
手动模拟过程:
- 新的 j j j进入
- 判断 f [ i − 1 ] [ j ] − a [ g e t ( j + 1 ) ] f[i-1][j]-a[get(j+1)] f[i−1][j]−a[get(j+1)]与 s s s的大小,更新 s s s
- 判断 s + a [ g e t ( j ) ] s+a[get(j)] s+a[get(j)]和 f [ i ] [ j ] f[i][j] f[i][j]的大小,更新 f [ i ] [ j ] f[i][j] f[i][j]
原谅我偷懒
那么最大的
s
u
m
sum
sum就是最大的
f
[
n
]
[
i
]
f[n][i]
f[n][i]
这时第一行求处理完了
第二行
处理第二行,其实就是要记每个
f
[
i
]
[
j
]
f[i][j]
f[i][j]是由哪个
k
k
k转移过来的
开一个新的数组
g
[
i
]
[
j
]
g[i][j]
g[i][j]表示
I
D
ID
ID数组的第
i
i
i位选择
j
j
j的最大
s
u
m
sum
sum是从哪个
k
k
k转移过来的
在上述的更新
f
[
i
]
[
j
]
f[i][j]
f[i][j]的那一步里顺便更新
g
[
i
]
[
j
]
g[i][j]
g[i][j]
注意输出的时候,因为我们是由
g
[
1
]
[
]
g[1][]
g[1][]转移到
g
[
2
]
[
]
g[2][]
g[2][]转移到
g
[
3
]
[
]
g[3][]
g[3][]……最后转移到
g
[
n
]
[
]
g[n][]
g[n][],所以要
d
g
dg
dg输出
先别急着去打
发现,这里的
g
[
i
]
[
j
]
g[i][j]
g[i][j]只有
n
n
n个数
但题目要求的是
n
+
1
n+1
n+1个数
那么第
n
+
1
n+1
n+1个数是什么???
其实就是最大
f
[
n
]
[
i
]
f[n][i]
f[n][i]的
i
i
i
Code
#include<cstdio>
#include<iostream>
#define inf 1234567890
#define get(x) ((((x)-(i-1)*r)%n+n-1)%n+1)
using namespace std;
int n,r,i,j,s,ss,t,ans,a[3005],f[3005][3005],g[3005][3005];
void dg(int x,int before)
{
if (x!=0) dg(x-1,g[x][before]);
printf("%d ",before);
}
int main()
{
scanf("%d%d",&n,&r);
for (i=1;i<=n;i++)
scanf("%d",&a[i]);
for (i=1;i<=n;i++)
{
ss=-inf;
for (j=1;j<n;j++)
{
s=f[i-1][j]+a[get(j)];
if (s>ss)
{
ss=s;
t=j;
}
if (ss-a[get(j+1)]>f[i][j])
{
f[i][j]=ss-a[get(j+1)];
g[i][j]=t;
}
}
ss=-inf;
for (j=n-1;j>=1;j--)
{
s=f[i-1][j]-a[get(j+1)];
if (s>ss)
{
ss=s;
t=j;
}
if (ss+a[get(j)]>f[i][j])
{
f[i][j]=ss+a[get(j)];
g[i][j]=t;
}
}
}
ans=-inf;
for (i=1;i<n;i++)
if (f[n][i]>ans)
{
ans=f[n][i];
t=i;
}
printf("%d\n",ans);
dg(n,t);
return 0;
}