Fair Cut

from hackerrank
Li 和 Lu 两个人分整数,他们想分的尽量公平。公平度量为:
![](http://www.forkosh.com/mathtex.cgi? f(I) = \sum_ {i \in I}\sum_{j \in J}|a_i - a_j|)
其中![](http://www.forkosh.com/mathtex.cgi? I={i_1,i_2,...,i_k}, J = {1,...,n} \backslash I)
Li得到其中k个数,Lu得到剩下的数。

Input Format

第一行输入n (整数的数量) 和 k (Li得到的整数个数). 第二行输入n个整数,空格隔开。

Constraints
![](http://www.forkosh.com/mathtex.cgi?1 \leq k < n \leq 3000\1 \leq a_i \leq 10^9\15 % test case n \leq 20\45% test case n \leq 40)

Output Format

打印最小值的f

Sample Input 0

4 2
4 3 1 2

Sample Output 0

6

Explanation 0
![](http://www.forkosh.com/mathtex.cgi? I={2,4}, J = {1,3})
Sample Input 1

4 1
3 3 3 1

Sample Output 1

2

Explanation 1
![](http://www.forkosh.com/mathtex.cgi? I={1}, J = {2,3,4})

动规解

首先将数字排序,而后做一个背包问题:
![](http://www.forkosh.com/mathtex.cgi? dp[\alpha][\beta][\gamma] = min. \sum_ {i \in I}\sum_{j \in J}|a_i - a_j|;\ I=\beta,I \subset {1,...,\alpha};\J = {1,...,\alpha}\backslash I;\\sum_{i \in I} a_i = \gamma.)
每一步都有两个选择,将数字分给Li和Lu.
第一种情况,
第二种情况,
解就是:


be equal to (every number in is less or equal than , so we know how to resolve absolute value). In the second case we will get to the state and new function will be . The answer for the problem is .
This approach gives us pseudo-polynomial solution but it's not enough for the problem. In the first approach we noticed that information about sum of Li's numbers is enough to recalculate the function. Also it's clear that we express function for the new state as linear combination of function for the old state and sum of Li's numbers in the old state. This thought pushes us to extend dp state in the another way: minimal possible . To calculate we should consider two cases: if the last integer is Li's and if it's Lu's. In the first case intended value is
(similarly to the first approach). In the second case it is . Answer for the problem is . To obtain solution we should notice that with fixed and we have only one interesting (because in the end we are interested only in the state and changing of depends on changing of ).

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
#define mp make_pair
#define pb push_back
#define sz(x) ((int) (x).size())


#define X first
#define Y second

const int maxn = 3005;
ll a[maxn];
ll dp[2][maxn]; // minimal possible (unfairness - coef * (sum of Li's integers))

int main()
{
    int n, k;
    cin >> n >> k;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    sort(a, a + n);
    for (int i = 0; i <= 1; i++)
       for (int j = 0; j <= k; j++)

              dp[i][j] = (i==0 && j==0?0ll:(ll)1e18);
    ll psum = 0ll;
    int coef;
    for (int i = 1; i <= n; i++)
    {
       for (int j = 0; j <= k; j++)
         {
            coef = (k-j)*2 - (n-i);
            dp[i&1][j] = min(dp[(i-1)&1][j] + (ll)j * a[i-1],  //Lu's
              (j>0 ? dp[(i-1)&1][j-1] - psum + (ll)coef * a[i-1] + (ll)(i-j) * a[i-1] : (ll)1e18));

         }
       psum += a[i-1];
    }
    cout << dp[n&1][k] << endl;
    return 0;
}

贪心解【from Discussion

根据物理的“平衡定律law of equilibium”, 这道题相当于求一个电势平衡。
The optimal cut is independent of the numbers, but only depends on their order. For example, if there are N=10 numbers to cut, and one person gets K=3 numbers, the best cut will be 0001010100, which means we first sort the 10 numbers in ascending order A[1]<=A[2]<=...<=A[10], and give the 0s to one person and the 1s to another. The strategy is to place the 01-string repetition (the "010101" in the example) as close to the middle of the whole string as possible. If K*2>N, redefine K to be N-K (switching the 0s and 1s). The intuition behind this greedy strategy comes from physics. The unfairness is like an interaction potential to be minimized. The 0s and 1s attract each other and form an ionic crystal in the middle of a positive charge background.

n, k = map(int, raw_input().split(' '))
l = map(int, raw_input().split(' '))
l.sort()
if k > n / 2:
    k = n - k
t = (n-2*k) / 2
if (n - 2*k)%2 == 0:
    dig_str = '0'* t + '01' * k + '0' * t
else:
    dig_str = '0'* (t + 1) + '10' * k + '0' * t
I = [i for i in range(n) if dig_str[i] == '1']
J = [i for i in range(n) if dig_str[i] == '0']
print sum([abs(l[i]-l[j]) for i in I for j in J])
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 惕胖子们了。 首先鹅肥肝的生产过程是非常悲惨的,幼鹅在长到12周的时候就被塞进小笼子,把脖子从栅栏中露出来,固定在...
    腴姿乐纤阅读 1,850评论 0 0
  • 碗所能撑起的情 比不上 流水的意 不被看好的 往往是 碗塑了水的形 格格不入 又相得益彰 愿碗的美丽 不负水的洒脱
    雨后的日子阅读 1,517评论 2 1
  • 20140721 西安的天气重复着高温红色预警。天气的炎热让人的心也变得浮躁起来。 夜里的温度是最让人感觉到舒服的...
    刘牧moira阅读 1,607评论 0 0

友情链接更多精彩内容