1144. The Emperor's Riddle

Time limit: 1.0 second
Memory limit: 4 MB

Background

In the olden times there was a young emperor who was the bravest, wisest, richest, most handsome in the whole world. He had proven himself in endless of battles, quests, and victories but his court was not happy because he had not appointed a queen yet. However, choosing a queen was not easy because of his high status and standard, the emperor wanted a girl not only beautiful but smart and kind as well. Lightning Knight - that was the young Emperor's name - sent his most trusted knights out to seek for a girl like that; and after a long time searching, the men brought back two of the most beautiful and intelligent girls in all the lands. They were two princess sisters from a faraway land. The older sister - Van Trinh - was mysterious and beautiful like the moon, while Thuy Linh - the younger one - was bright and lovely as the sun. They were both famous for being kind, gentle, and intelligent to their people, and as many girls before them, they both fell truly, madly, deeply in love with the handsome emperor at first sight.
Now, the Emperor had to face the hardest test of all: to pick just one in these two sisters to become his rightful and beloved queen and lay the world under her feet. After countless sleepless nights, the Emperor sought out a just solution. He thought of a riddle and announced to the two princesses and the court that he would marry the first one who bring the right answer to his desk.

Problem

At the same time with the above event, the Emperor had just won the most important battle to unite all the lands in the world. That was two good news in such a short time. Being the rich and generous emperor he was, the Emperor wanted to reward to all the brave and loyal generals with boxes of gold. The distribution was not easy and that's why he chose it as the riddle for Van Trinh and Thuy Linh. Centuries has passed since then, the Emperor and queen might have died and their romance might have been forgotten from our world, but the riddle still remains as one of the hardest tasks in the ancient books.
The Emperor wants to reward N boxes of gold to M generals. The i-th box has the value of Ai. Now the Emperor wants to give N boxes to M generals so that the difference of gold between the general who receives the most gold and the general who receives the least gold is as small as possible. Note: a general can receive more than one box, and he must receive the whole box (i.e.: not half or 1/3 of box).

Input

The 1st line contains three positive integers N, M and K (N ≤ 10000, M ≤ 1000 and N ≥ M). K is the maximum result that the emperor accepts. The 2nd line contains N positive integers 0 < A1, A2, …, AN ≤ 1000.

Output

The 1st line contains one integer which is the minimum difference your program can find. In the next M lines, the i-th line contains the index of boxes rewarded to the i-th general.

Sample

input output
10 3 4
12 95 16 37 59 50 47 3 41 95
4
6 7 9 1
8 10 4 3
5 2
Problem Author: HNT 
Difficulty: 1778
 
题意:把n个数分成m组,要使极差小于k,问其中一组方案。
分析:这是一道很不错的题。
一定要注意到,这题不需要求精确解。
首先有一个显而易见的贪心。
把数字从大到小排序,然后分给目前总和最小的组。
然而这个贪心只能求得较优解,在大多数情况下,无法求得满足极差小于k的解。
 
。。。。然而有一种很不错的方法叫做调整法。。。
首先,有一个经典问题:有两组数,要让它们两两配对,使得这些数对之和的极差最小,怎么配对?
显然是一组从大到小,一组从小到大匹配。
那么回到原题。
我们先随便将n个数分成m组。
然后将每组树再随机分成两组,记为A组,B组。
然后问题就变成了经典问题:有2组m个数,要让它们两两配对,是的这些数对之和极差最小。
我们利用这种思想将A组,B组重新分配。
根据那个经典问题的思想,新的分配方案不会比旧的分配方案要差。
所以我们不断进行这一过程,直到极差不超过k。
 
实际实现的过程当中,我们可以采用贪心与调整法相结合的方法,
因为调整法毕竟调整的速度比较慢,容易超时。
 
 
 /**
Create By yzx - stupidboy
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm>
#include <map>
#include <set>
#include <ctime>
#include <iomanip>
using namespace std;
typedef long long LL;
typedef double DB;
#define MIT (2147483647)
#define INF (1000000001)
#define MLL (1000000000000000001LL)
#define sz(x) ((int) (x).size())
#define clr(x, y) memset(x, y, sizeof(x))
#define puf push_front
#define pub push_back
#define pof pop_front
#define pob pop_back
#define ft first
#define sd second
#define mk make_pair inline int Getint()
{
int Ret = ;
char Ch = ' ';
bool Flag = ;
while(!(Ch >= '' && Ch <= ''))
{
if(Ch == '-') Flag ^= ;
Ch = getchar();
}
while(Ch >= '' && Ch <= '')
{
Ret = Ret * + Ch - '';
Ch = getchar();
}
return Flag ? -Ret : Ret;
} const int N = , M = ;
int n, m, k, arr[N];
priority_queue<pair<int, int> > index, boxes;
int sum[M], belong[N], tag[N];
int tmp[N];
int type[][M], ranks[M], to[M]; inline void Input()
{
scanf("%d%d%d", &n, &m, &k);
for(int i = ; i <= n; i++) scanf("%d", &arr[i]);
} inline int Check()
{
for(int i = ; i <= m; i++) sum[i] = ;
for(int i = ; i <= n; i++) sum[belong[i]] += arr[i];
int mx = -INF, mn = INF;
for(int i = ; i <= m; i++)
mx = max(mx, sum[i]),
mn = min(mn, sum[i]);
return (mx - mn) - k;
} inline bool Compare(int t, int a, int b)
{
return type[t][a] < type[t][b];
} inline bool CmpUp(int a, int b)
{
return Compare(, a, b);
} inline bool CmpDown(int a, int b)
{
return Compare(, b, a);
} inline void Solve()
{
srand(time());
//sort(arr + 1, arr + 1 + n, greater<int>() );
for(int i = ; i <= m; i++) index.push(mk(-sum[i], i));
for(int i = ; i <= n; i++) boxes.push(mk(arr[i], i));
for(int i = ; i <= n; i++)
{
int u = index.top().sd, v = boxes.top().sd;
index.pop(), boxes.pop();
sum[u] += arr[v], belong[v] = u;
index.push(mk(-sum[u], u));
} int now;
while((now = Check()) > )
{
//printf("%d\n", now);
for(int i = ; i <= n; i++)
tag[i] = rand() & ; for(int t = ; t < ; t++)
for(int i = ; i <= m; i++)
type[t][i] = ;
for(int i = ; i <= n; i++)
type[tag[i]][belong[i]] += arr[i]; for(int t = ; t < ; t++)
{
for(int i = ; i <= m; i++)
ranks[i] = i;
if(t == )
sort(ranks + , ranks + + m, CmpUp);
else sort(ranks + , ranks + + m, CmpDown); for(int i = ; i <= m; i++) to[ranks[i]] = i;
for(int i = ; i <= n; i++)
if(tag[i] == t)
tmp[i] = to[belong[i]];
} for(int i = ; i <= n; i++)
belong[i] = tmp[i];
} int ans = Check() + k;
printf("%d\n", ans);
vector<int> answer[M];
for(int i = ; i <= n; i++) answer[belong[i]].pub(i);
for(int i = ; i <= m; i++)
{
int length = sz(answer[i]);
for(int j = ; j < length - ; j++)
printf("%d ", answer[i][j]);
if(length) printf("%d\n", answer[i].back());
/*int p = 0;
for(int j = 0; j < length - 1; j++)
{
printf("%d ", arr[answer[i][j]]);
p += arr[answer[i][j]];
}
if(length)
{
printf("%d ", arr[answer[i].back()]);
p += arr[answer[i].back()];
}
printf("%d\n", p);*/
}
//sfor(int i = 1; i <= m; i++) printf("%d ", sum[i]);
} int main()
{
freopen("a.in", "r", stdin);
freopen("a.out", "w", stdout);
Input();
Solve();
return ;
}

ural 1144. The Emperor's Riddle的更多相关文章

  1. URAL 1994 The Emperor's plan 求组合数 大数用log+exp处理

    URAL 1994 The Emperor's plan 求组合数 大数用log #include<functional> #include<algorithm> #inclu ...

  2. URAL 1994 The Emperor's plan

    期望$dp$. $dp[i][j]$表示第$1$种人有$i$个,第$2$种人有$j$个的情况下,到达目标状态的期望值.初始化$dp[i][0]=i$. 枚举一下这个状态死多少人,取个$max$,最后$ ...

  3. POJ 1144

    http://poj.org/problem?id=1144 题意:给你一些点,某些点直接有边,并且是无向边,求有多少个点是割点 割点:就是在图中,去掉一个点,无向图会构成多个子图,这就是割点 Tar ...

  4. 网页闯关游戏(riddle webgame)--H5刮刮卡的原理和实践

    前言: 之前编写了一个网页闯关游戏(类似Riddle Game), 除了希望大家能够体验一下我的游戏外. 也愿意分享编写这个网页游戏过程中, 学到的一些知识. 对于刮刮卡, 想必大家都很熟悉, 也很喜 ...

  5. 后缀数组 POJ 3974 Palindrome && URAL 1297 Palindrome

    题目链接 题意:求给定的字符串的最长回文子串 分析:做法是构造一个新的字符串是原字符串+反转后的原字符串(这样方便求两边回文的后缀的最长前缀),即newS = S + '$' + revS,枚举回文串 ...

  6. ural 2071. Juice Cocktails

    2071. Juice Cocktails Time limit: 1.0 secondMemory limit: 64 MB Once n Denchiks come to the bar and ...

  7. ural 2073. Log Files

    2073. Log Files Time limit: 1.0 secondMemory limit: 64 MB Nikolay has decided to become the best pro ...

  8. ural 2070. Interesting Numbers

    2070. Interesting Numbers Time limit: 2.0 secondMemory limit: 64 MB Nikolay and Asya investigate int ...

  9. ural 2069. Hard Rock

    2069. Hard Rock Time limit: 1.0 secondMemory limit: 64 MB Ilya is a frontman of the most famous rock ...

随机推荐

  1. ASP.NET MVC中解决日志并发处理log4net

    本章主要内容是将异常信息写到队列中,然后通过线程写到文本文件中,速度非常快,没有阻塞和延迟加载 1.首先在Model中建一个类MyExceptionAttribute.cs public class ...

  2. Linux系统入门学习:在curl中设置自定义的HTTP头

    http://www.linuxidc.com/Linux/2015-02/114220.htm

  3. 字符识别(模板匹配&BP神经网络训练)

    http://blog.csdn.net/zhang11wu4/article/details/7585632

  4. vim、gvim加载文件慢

    1. strace -f -T -o vim.strace vim 2. vim --startuptime "vim-time.txt" 3. gvim -f

  5. Windows 10 周年更新正式版下载 + win10 快捷键

    Windows 10 周年更新正式版  360云资源总汇(施工中): https://yunpan.cn/c6Svi7Az52XBs (提取码:e5dd)今后提到周年更新版.1607版或RS1版,都是 ...

  6. linux命令**50

    1.ls命令 命令格式: ls [选项] [目录名] 命令功能: 列出目标目录中所有的子目录和文件. 常用参数: -a,列出所有文件包括隐藏文件 -l,列出详细信息,文件大小一般以字节大小显示 -h, ...

  7. 学习一下《JavaEE开发的颠覆者 Spring Boot实战 》

    SPRING,绕不过去的.

  8. 扩展LV

    LVM最大的特性就是可以弹性调整磁盘容量下面扩展一个已经存在的LV [root@ol6--rac1 mnt]# lvdisplay --- Logical volume --- LV Path /de ...

  9. PHP实现上一篇、下一篇

    //php实现上一篇.下一篇 获取当前浏览文章id $id = isset($_GET[ ? intval($_GET['id']) : ""; 下一篇文章 $query = my ...

  10. [Eclipse] Eclipse配置Tomcat插件

    1 . Eclipse IDE 3.6 for Java EE Developersat- 5.5.28 或者以上版本 : 2 . 安装 Tomcat 插件 , 文件名: tomcatPluginV3 ...