文章目录
F.Sorting Pancakes
题意:
给你
n
(
n
≤
250
)
n(n\leq 250)
n(n≤250)个整数的序列
a
(
∑
a
i
≤
250
)
a(\sum a_i\leq250)
a(∑ai≤250),你可以用
1
1
1的花费将
a
i
−
1
a_i-1
ai−1,使
a
i
+
1
a_{i+1}
ai+1或
a
i
−
1
+
1
a_{i-1}\text{ }+1
ai−1 +1,问最小用多少的花费可将序列变为不上升序列
思路:
由于本题数据范围极小,于是想到费用流,但是由于最终变换出来的序列未知,所以无法实现
于是考虑对于每一个
a
i
a_i
ai,最终其变为
b
i
b_i
bi,
a
a
a的前缀和为
s
a
sa
sa,
b
b
b的前缀和为
s
b
sb
sb
如果写过糖果传递,一道与本题类似的题目,不难知道,最终的结果为
∑
∣
s
a
i
−
s
b
i
∣
\sum |sa_i-sb_i|
∑∣sai−sbi∣
证明如下:
令
c
i
=
a
i
−
b
i
c_i=a_i-b_i
ci=ai−bi。在位置
1
1
1,我们需要
∣
c
1
∣
|c_1|
∣c1∣次操作,如果
c
1
<
0
c_1<0
c1<0表示位置
1
1
1向
2
2
2拿了
∣
c
1
∣
|c_1|
∣c1∣个,反之,表示给了
c
1
c_1
c1个
当到了位置
2
2
2,此时位置
2
2
2的数字应该是
a
2
+
a
1
−
b
1
a_2+a_1-b_1
a2+a1−b1,还应该操作
a
2
+
a
1
−
b
1
−
b
2
a_2+a_1-b_1-b_2
a2+a1−b1−b2来向位置
3
3
3多退少补
于是以此类推
i
=
1
a
1
−
b
1
i
=
2
a
1
−
b
1
+
a
2
−
b
2
i
=
3
a
1
−
b
1
+
a
2
−
b
2
+
a
3
−
b
3
.
.
.
i=1 \text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }a_1-b_1\\i=2 \text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }a_1-b_1+a_2-b_2\\ \\i=3 \text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }\text{ }a_1-b_1+a_2-b_2+a_3-b_3 \\...
i=1 a1−b1i=2 a1−b1+a2−b2i=3 a1−b1+a2−b2+a3−b3...
答案为
∑
∣
s
a
i
−
s
b
i
∣
\sum |sa_i-sb_i|
∑∣sai−sbi∣
本题的正确解法为
D
P
DP
DP
定义
d
p
{
i
,
j
,
k
}
dp\{i,j,k\}
dp{i,j,k}表示在前
i
i
i个数中,前
i
i
i位之和为
j
j
j,第
i
i
i位上的数字为
k
k
k,此时前
i
i
i位数字需要的操作次数
如果第
i
−
1
i-1
i−1位数字为
p
p
p
d
p
[
i
]
[
j
]
[
k
]
=
d
p
[
i
−
1
]
[
j
−
k
]
[
p
]
+
a
b
s
(
s
a
i
−
s
b
i
)
dp[i][j][k]=dp[i-1][j-k][p]+abs(sa_i-sb_i)
dp[i][j][k]=dp[i−1][j−k][p]+abs(sai−sbi)
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=2e5+7;
int f[255][255][255];
int a[255],sum[255];
int main()
{
memset(f,0x3f,sizeof(f));
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
if(n==1)
{
puts("0");return 0;
}
int ans=inf;
for(int i=0;i<=m;i++) f[1][i][i]=abs(a[1]-i);
for(int i=2;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int pre=0;pre<=j;pre++)
{
for(int k=0;k<=pre&&k+pre<=j;k++)
{
f[i][j][k]=min(f[i][j][k],f[i-1][j-k][pre]+abs(sum[i]-j));
if(i==n&&j==m) ans=min(ans,f[i][j][k]);
}
}
}
}
printf("%d\n",ans);
}
在此基础上还可以继续优化
由于转移
d
p
{
i
,
j
,
k
}
dp\{i,j,k\}
dp{i,j,k}时,只与
∣
s
a
i
−
s
b
i
∣
|sa_i-sb_i|
∣sai−sbi∣和
d
p
{
i
−
1
,
j
−
k
,
p
}
dp\{i-1,j-k,p\}
dp{i−1,j−k,p}有关,所以可以预处理
d
p
{
i
−
1
,
j
−
k
,
p
}
dp\{i-1,j-k,p\}
dp{i−1,j−k,p}最小后缀,来少一维循环,时间复杂度
O
(
n
3
)
O(n^3)
O(n3)