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. Linux C程序内存空间

    linux下内存空间布置: 一个典型的Linux C程序内存空间由如下几部分组成: 代码段(.text).这里存放的是CPU要执行的指令.代码段是可共享的,相同的代码在内存中只会有一个拷贝,同时这个段 ...

  2. 解决git客户端MINGW32下的“Could not open a connection to your authentication agent.”

    使用git, 下载客户端后想进行和github 进行ssh 互通 出现以下情况: hadoop@deng-PC MINGW32 ~/.ssh$ ssh-add ~/.ssh/id_rsaCould n ...

  3. nginx 配一个简单的静态文件服务器 和一个虚似机

    下面是个图片服务器: server { listen ; server_name img.xxx.xxx.com; root /data/site/img.xxx.xxx.com; access_lo ...

  4. 与你相遇好幸运,Tippecanoe在Centos下の安装

    全新的CentOS 7 x86_64 安装编译工具 yum install -y gcc automake autoconf libtool make yum insyall -y gcc gcc-c ...

  5. JAVA基础学习之IP简述使用、反射、正则表达式操作、网络爬虫、可变参数、了解和入门注解的应用、使用Eclipse的Debug功能(7)

    1.IP简述使用//获取本地主机ip地址对象.InetAddress ip = InetAddress.getLocalHost();//获取其他主机的ip地址对象.ip = InetAddress. ...

  6. SQL Server 2014 BI新特性(一)五个关键点带你了解Excel下的Data Explorer

    Data Explorer是即将发布的SQL Server 2014里的一个新特性,借助这个特性讲使企业中的自助式的商业智能变得更加的灵活,从而也降低了商业智能的门槛. 此文是在微软商业智能官方博客里 ...

  7. Codeforces Round #363 Fix a Tree(树 拓扑排序)

    先做拓扑排序,再bfs处理 #include<cstdio> #include<iostream> #include<cstdlib> #include<cs ...

  8. Windows 历史

  9. android 入门-防微信拍摄视频 按钮事件处理

    package com.cc.view; import com.cc.R; import com.cc.R.layout; import com.cc.R.menu; import android.o ...

  10. hdu 4273 2012长春赛区网络赛 三维凸包中心到最近面距离 ***

    新模板 /* HDU 4273 Rescue 给一个三维凸包,求重心到表面的最短距离 模板题:三维凸包+多边形重心+点面距离 */ #include<stdio.h> #include&l ...