luogu P6831 [IOI2020]嘉年华奖券
作者:互联网
题面传送门
首先看到题面中保证\(n\)为偶数,所以可以从这一个方面来推。
稍微用初一上的内容推一下就可以发现:对于一次取得升序序列\(a\),其权值为\(\sum\limits_{i=\frac{n}{2}+1}^{n}{a_i}-\sum\limits_{i=1}^{\frac{n}{2}}{a_i}\)
那么一定是在满足每种颜色\(k\)个的颜色下,最大的\(\frac{nk}{2}\)个为前面,其余为后面。
具体的,我们首先假设所有的数都是负的,然后考虑将一个数转化为正的,那么最优就是转化为所处颜色最大值。因为这个有单调性,所以可以用堆维护。
这样就可以求出答案。
接下来考虑怎么构造。
有一个显然的结论:前面的任何一个数都不小于后面的任何一个数,因为如果有一个小于的,那么就可以两边互换,就不是最优。
有了这个结论,就可以任意分组,但是还有颜色的限制。
这个限制考虑仍然用堆维护,找到含有前面元素个数最多的颜色,最先使用,其所对应的也是后面颜色最少的,这样能保证一定能匹配。
时间复杂度\(O(nmlogm)\)
代码实现:
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cstring>
using namespace std;
int a[1539][1539],n,m,k,h[1539],flag[1539];
struct ques{
int w,id;
bool operator <(const ques &x)const{return w<x.w;}
}w[1539];
std::priority_queue<ques> q;
struct yyy{int x,y;};
extern "C" void allocate_tickets(std::vector<std::vector<int> > s);
extern "C" long long find_maximum(int k,std::vector<std::vector<int> > x){
long long ans=0;register int i,j;register ques tmp;register yyy now;
n=x.size();m=x[0].size();
for(i=0;i<n;i++){
for(j=0;j<m;j++) a[i+1][j+1]=x[i][j];
}
for(i=1;i<=n;i++) sort(a[i]+1,a[i]+m+1);
for(i=1;i<=n;i++)h[i]=k,q.push((ques){a[i][k]+a[i][m],i});
for(i=1;i<=n/2*k;i++){
tmp=q.top();q.pop();
h[tmp.id]--;if(h[tmp.id]) q.push((ques){a[tmp.id][m-k+h[tmp.id]]+a[tmp.id][h[tmp.id]],tmp.id});
}
for(i=1;i<=n;i++){
for(j=m-k+h[i]+1;j<=m;j++) ans+=a[i][j];
for(j=1;j<=h[i];j++)ans-=a[i][j];
for(j=0;j<m;j++) x[i-1][j]=-1;
}//printf("%d\n",g.size());
while(!q.empty()) q.pop();
for(i=1;i<=n;i++) q.push((ques){k-h[i],i});
for(i=1;i<=k;i++){
for(j=1;j<=n/2;j++) w[j]=q.top(),q.pop(),x[w[j].id-1][m-w[j].w]=i-1,flag[w[j].id]=1;
for(j=1;j<=n/2;j++) w[j].w--,q.push(w[j]);
for(j=1;j<=n;j++){
if(!flag[j]) x[j-1][--h[j]]=i-1;
else flag[j]=0;
}
}
allocate_tickets(x);
return ans;
}
/*int x;
std::vector<std::vector<int> > sa;
std::vector<int> sb;
void allocate_tickets(std::vector<std::vector<int> > s){
register int i,j,n=s.size(),m=s[0].size();
for(i=0;i<n;i++){
for(j=0;j<m;j++) printf("%d ",s[i][j]);printf("\n");
}
}
int main(){
freopen("1.in","r",stdin);
register int i,j;
scanf("%d%d%d",&n,&m,&k);
for(i=1;i<=n;i++){
sb.clear();
for(j=1;j<=m;j++) scanf("%d",&x),sb.push_back(x);
sa.push_back(sb);
}
printf("%lld ",find_maximum(k,sa));
}*/
标签:std,int,luogu,IOI2020,vector,奖券,include,1539,size 来源: https://www.cnblogs.com/275307894a/p/14374132.html