题意

有\(N\)个人,现在你要从中选出\(K\)个人出来,然后让这\(K\)个人一起参加\(K\)场比赛。其中,每个人都要参加所有的比赛。

定义其中一场比赛的得分为这\(K\)个人的得分的最大值。然后定义这个队的得分为\(K\)场比赛的得分的加和。

例如,\(K=3\)时,有一支3个人的队伍,一共打3场比赛。第1个人在3场比赛中的得分分别为\((4, 5, 3)\),第2个人在3场比赛中的得分分别为 \((7, 3, 6)\), 第3个人在3场比赛中的得分分别为 \((3, 4, 5)\)。那么这个队伍的总得分就是\(7+5+6=18\)。

现在你要求出的是,总分最第\(C\)大的队伍的得分是多少。定义两个队伍不同,当且仅当存在两个两个队伍的人的编号不同。

输入格式

第一行3个整数分别表示\(N,K,C\);

接下来N行,每行K个整数,表示每个人在每场比赛中的得分。

输出格式

一行,输出得分第\(C\)大的队伍的得分。

样例

Input

5 4 4

7 0 4 9

3 0 8 4

1 1 3 7

5 1 3 4

4 2 2 9

Output

24

数据范围

1.(13 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 2, 1 ≤ C ≤ 2 000.

2.(31 points) 1 ≤ N ≤ 40, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000.

3.(24 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000, 每个人的分数大小不超过10.

4.(32 points) 1 ≤ N ≤ 500, 1 ≤ K ≤ 6, 1 ≤ C ≤ 2 000.

时间限制

\(2\ sec / 30\ sec\)

思路

首先声明这是自己的方法,没有看官方题解...

首先求一个得分最大的队伍出来,怎么求呢?

就是让每一场比赛的得分都尽量大,也就是取所有人中这场比赛得分最大的那个人。然后这样子选完之后可能没有选齐K个人,那么剩余的位置就随便找人来补齐就好了。

然后仿照所有的求第k大的题目的做法,把这个队伍塞到一个大根堆(priority_queue)中去,每次都从队首取出一个当前的最大答案,然后用这个队伍进行拓展,塞入其它没有出现过的其他队伍。

如何拓展呢?

最暴力的想法是,每次都将这个队伍中的一个人换成另外一个人,然后在确定了这支新的队伍没有出现过之后,就将这支队伍也塞到优先队列中去。

如何判断之前是否重复呢?我用的是Hash,然后把Hash值塞到一个set里面去,就可以简单的判重了。

考虑一下时间复杂度:一共要取出C次,就是\(O(C)\),每次都要枚举将哪个人替换掉,也就是\(O(K)\)。还要枚举替换成哪个人,也就是\(O(N)\)。替换了之后,还要算出新的队伍的得分是多少,也就是\(O(K^2)\)的。然后还有set和priority_queue的时间复杂度,设为\(Const\)。那么总的时间复杂度就是\(O(N*K^3*C*Const)\),大概有\(216,000,000+\),好像跑不过...

考虑剪枝。考虑替换一个人的时候,只在N个人当中选出那些替换之后会使得答案变小或不变的那些人进行判重,判断没有出现过之后再选取其中的最大值进行扩展。这样子总共扩展出来的节点数就有原来的\(C*K*N\)变为了\(C*K\),优先队列和set部分的时间就变小了。然后枚举的时候,也被剪掉了不少。这样子就可以跑到0.3s~0.4s左右。

代码

实现的有点丑,但是算法还是很简单暴力的。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define MAXN 500
#define MAXK 6
#define MAXC 2000
#define MO 10000007
using namespace std;
typedef long long LL;
struct state
{
int val;LL st;
state(){};
state(int _val,LL _st):val(_val),st(_st){};
};
bool operator < (const state &A,const state &B){return A.val<B.val;}
priority_queue<state> que;
struct node
{
LL x;
node *nxt;
}nd[MAXC*MAXN*MAXK+5];
node *ncnt=&nd[0],*Adj[MO+5];
int n,k,c,tmp[MAXK+1];
int scr[MAXN+5][MAXK+1];
LL Encode(int *seq)
{
LL ret=0;
for(int i=1;i<=k;i++)
ret=1LL*ret*n+(1LL*seq[i]-1);
return ret;
}
void Decode(LL val,int *seq)
{
for(int i=k;i>=1;i--)
seq[i]=val%n+1,val/=n;
}
int GetVal(int *seq)
{
int ret=0;
for(int j=1;j<=k;j++)
{
int mxval=0;
for(int i=1;i<=k;i++)
mxval=max(mxval,scr[seq[i]][j]);
ret+=mxval;
}
return ret;
}
void Print(int *seq)
{
for(int i=1;i<=k;i++)
printf("%d ",seq[i]);
printf("\n");
}
void Insert(LL x)
{
int id=x%MO;
node *p=++ncnt;
p->x=x;
p->nxt=Adj[id];
Adj[id]=p;
}
bool Find(LL x)
{
int id=x%MO;
for(node *p=Adj[id];p!=NULL;p=p->nxt)
if(p->x==x)
return true;
return false;
}
int Solve()
{
static int tmp1[MAXK+5],tmp2[MAXK+5];
static bool sp[MAXN+5];
state fro;
for(int tmn=1;tmn<c;tmn++)
{
fro=que.top();que.pop();
Decode(fro.st,tmp1);
for(int i=1;i<=k;i++)
sp[tmp1[i]]=1;
for(int i=1;i<=k;i++)
{
LL mxst;
int mxval=-1;
for(int j=1;j<=n;j++)
if(sp[j]==false)
{
for(int p=1;p<=k;p++)
tmp2[p]=tmp1[p];
tmp2[i]=j;
int val=GetVal(tmp2);
if(val>fro.val) continue;
if(val>mxval)
{
sort(tmp2+1,tmp2+1+k);
LL st=Encode(tmp2);
if(Find(st))
continue;
mxval=val,mxst=st;
}
}
if(mxval==-1)
continue;
Insert(mxst);
Decode(mxst,tmp2);
que.push(state(mxval,mxst));
}
for(int i=1;i<=k;i++)
sp[tmp1[i]]=0;
}
return que.top().val;
}
int main()
{
freopen("olymp.in","r",stdin);
freopen("olymp.out","w",stdout);
scanf("%d %d %d",&n,&k,&c);
for(int i=1;i<=n;i++)
for(int j=1;j<=k;j++)
scanf("%d",&scr[i][j]);
for(int j=1;j<=k;j++)
{
int mxpos=-1;
for(int i=1;i<=n;i++)
if(mxpos==-1||scr[mxpos][j]<scr[i][j])
mxpos=i;
tmp[j]=mxpos;
}
sort(tmp+1,tmp+1+k);
int len=unique(tmp+1,tmp+1+k)-tmp-1;
for(int i=len+1;i<=k;i++)
for(int j=1;j<=n;j++)
{
bool Find=false;
for(int p=1;p<i&&Find==false;p++)
if(tmp[p]==j)
Find=true;
if(Find==false)
{
tmp[i]=j;
break;
}
}
sort(tmp+1,tmp+1+k);
LL ret=Encode(tmp);
Insert(ret);
que.push(state(GetVal(tmp),ret));
int ans=Solve();
printf("%d\n",ans);
return 0;
}
/*
5 4 4
7 0 4 9
3 0 8 4
1 1 3 7
5 1 3 4
4 2 2 9 */

[BOI2019][第K大问题][暴力剪枝]D2T1 Olympiads的更多相关文章

  1. poj 3714 Raid【(暴力+剪枝) || (分治法+剪枝)】

    题目:  http://poj.org/problem?id=3714 http://acm.hust.edu.cn/vjudge/contest/view.action?cid=27048#prob ...

  2. 区间第k大问题 权值线段树 hdu 5249

    先说下权值线段树的概念吧 权值平均树 就是指区间维护值为这个区间内点出现次数和的线段树 用这个加权线段树 解决第k大问题就很方便了 int query(int l,int r,int rt,int k ...

  3. 整体二分初探 两类区间第K大问题 poj2104 & hdu5412

    看到好多讲解都把整体二分和$CDQ$分治放到一起讲 不过自己目前还没学会$CDQ$分治 就单独谈谈整体二分好了 先推荐一下$XHR$的 <浅谈数据结构题的几个非经典解法> 整体二分在当中有 ...

  4. [NBUT 1458 Teemo]区间第k大问题,划分树

    裸的区间第k大问题,划分树搞起. #pragma comment(linker, "/STACK:10240000") #include <map> #include ...

  5. HDU 4876 ZCC loves cards(暴力剪枝)

    HDU 4876 ZCC loves cards 题目链接 题意:给定一些卡片,每一个卡片上有数字,如今选k个卡片,绕成一个环,每次能够再这个环上连续选1 - k张卡片,得到他们的异或和的数,给定一个 ...

  6. HDU 6382 odds (暴力 + 剪枝优化)

    odds Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Subm ...

  7. Codeforces A. Playlist(暴力剪枝)

    题目描述: Playlist time limit per test 2 seconds memory limit per test 256 megabytes input standard inpu ...

  8. 暴力剪枝——cf1181C

    暴力求长度为len时,以i,j为左上角的旗子的数量 不剪枝的话复杂度是n*n*m*n,必定超时 两个可以剪枝的地方:如果格子[i,j]可以作为长度为len的旗子的左上角,那么其必定不可以作为长度> ...

  9. HDU 5839 Special Tetrahedron (2016CCPC网络赛08) (暴力+剪枝)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5839 在一个三维坐标,给你n个点,问你有多少个四面体(4个点,6条边) 且满足至少四边相等 其余两边不 ...

随机推荐

  1. SP419/422 TRANSP(2) - Transposing is Fun

    首先可以发现转置本质上就是一个置换,问题就转化为求一个排列排成有序的最少次数. 这是一个经典问题,答案为点数减循环置换的个数,考虑如何求循环置换. 发现有两个特殊性质:置换为转置,矩阵的边长为 \(2 ...

  2. Java面试必问之线程池的创建使用、线程池的核心参数、线程池的底层工作原理

    一.前言 大家在面试过程中,必不可少的问题是线程池,小编也是在面试中被问啥傻了,JUC就了解的不多.加上做系统时,很少遇到,自己也是一知半解,最近看了尚硅谷阳哥的课,恍然大悟,特写此文章记录一下!如果 ...

  3. 【转】MySql根据经纬度获取附近的商家

    创建geo表 create table geo( geo_id INT NOT NULL AUTO_INCREMENT, lng float NOT NULL, lat float NOT NULL, ...

  4. argc 和 argv

    转载请注明来源:https://www.cnblogs.com/hookjc/ 如果用C寫一般的命令列工具,常透過main函式的argc,argv來取得使用者所輸入的命令參數.int main(int ...

  5. Volatile关键字和ThreadLocal变量的简单使用

    原创:转载需注明原创地址 https://www.cnblogs.com/fanerwei222/p/11812459.html package thread; /** * volatile关键字和T ...

  6. 一张图让你看懂 iPhone 各种分辨率问题! #DF

    话不多说,直接看图! Source: paintcodeapp.com

  7. iOS中通过链接地址打开指定APP并传参 by徐文棋

    基于项目需要,有时候需要通过一个链接,或者二维码扫描来直接打开我们所开发的客户端. 当然了.客户端也不仅仅是需要被打开,而且还要跳到相应的页面去,因此这里需要传参. 客户端想用链接打开,必须要在inf ...

  8. fiddler模拟2

    在解决日常的支持需求中,经常会遇到一些用户反馈一些无法简单复现的bug,有很大一部分的bug是由于用户自身的网络环境波动,或者是本身网络环境就较为恶劣,而服务在面对这种恶劣的网络环境的健壮性不够,导致 ...

  9. 针对某p社游戏某整合包的研究

    软件分析 垃圾re手 最近在玩群星 创意工坊里面下载了整合包 进群下载排序文件后竟然发现要付费() 28R够吃一顿好的 马上来分析一下这个软件 这是一个四版整合包的mod安装器 其中樱花远征和新星纪元 ...

  10. Maven依赖,去哪儿找

    1. 前言 maven是作为Javer日常开发中必不可少的工具,但是很多人对于它的使用也只是仅限于的几个功能. 前几天在使用一个依赖总是说找不到该依赖,但是在中央仓库中的确存在该构建.这个问题让我很困 ...