[NOIP2017模拟]德充符

来源:互联网 发布:windows 2012 mse 编辑:程序博客网 时间:2024/06/05 23:55

题目描述
申徒嘉和郑子产都是伯昏无人的学生,子产因为申徒嘉是残疾人,非常看不起他,于是想要刁难他。
子产给了申徒嘉 n个数 a1,a2…an。
现在他要求申徒嘉重新排列这些数,使得 H=||…|b1-b2|-b3|-b4|-…|-bn|最大(b是a重新排列后的序列,|x|表示取 x的绝对值)
申徒嘉对于吹逼很擅长,但是数学就不怎么样了,于是他请你来帮帮他。

输入格式
第一行一个数 n,接下来一行 n个数,第 i个数表示 a[i]
n<=300
1<=a[i]<=300
对于 30%的数据,n<=10

输出格式
输出一行一个整数表示答案

样例数据
输入
4
3 6 7 8
输出
6

备注
【样例说明】
对于第一组样例:
|||6-8|-3|-7| = 6

分析:
【难度】中
【知识点】DP
【算法分析】
乱搞做法:
因为答案不超过 300,而且似乎要控制只有少数特定的排列使得答案最大是不太容易的,因此不断随机打乱更新答案,就很容易得到最大值。

标准做法:
考虑堆积木模型:
现在你有两个塔,初始高度都是 0,n 个积木,每个积木的高度是 a[i],现在你每次可以选一个积木放到当前高度较矮的那个塔上,最大化最后两个塔的高度差
容易证明这个问题和原问题等价
现在考虑怎么解决这个问题,我们发现每次只能往较矮的那个塔上放积木这个限制非常麻烦。
不难证明最高的一个积木一定是最后放的(试想把最高的积木移到中间上,结果一定不会变优)
现在我们把最高的一个积木拿掉,这样问题就变成了最小化高度差
如果要最小化高度差的话,每次只能往较矮的那个塔上放积木这个条件是没有用的(要得到最后的最优解,一定存在一种方案是满足这个限制的)
因此就去掉了这个限制,接下来愉快地DP 就好了。
设 F[i][k]表示只用前 i 个,两边的高度差达到 k可行不可行,转移;
转移:
if(f[i-1][k])
F[i][k+a[i]] = F[i][abs(k-a[i])] = true

代码:
乱搞做法orz

#include <stdio.h>#include <algorithm>#include <time.h>const int N = 300;int a[N + 10];int ABS(int a){    return a > 0 ? a : -a;}int main(){    freopen("dcf.in","r",stdin);    freopen("dcf.out","w",stdout);    srand(998244353);    int n = 0;    scanf("%d",&n);    for(int i = 1;i <= n;i++)        scanf("%d",a + i);    int res = 0;    for(int _t = 1;_t <= 100000;_t++)    {        std::random_shuffle(a + 1,a + 1 + n);        int now = a[1];        for(int i = 2;i <= n;i++)            now = ABS(now - a[i]);        if(res < now)            res = now;    }    printf("%d\n",res);    return 0;}

本题结。

原创粉丝点击