zoukankan      html  css  js  c++  java
  • [IOI2020]嘉年华奖券

    洛谷传送门


    这题的主要算法我确实想不出来……不愧是IOI的题。


    首先假如把一轮游戏的(a_i)从小到大排序,那么奖励数额(x_i=sum_{i=frac{n}{2}+1} ^ {n}a_i - sum _ {i = 1} ^ {frac{n}{2}}a_i).
    然后我们要求的就是(sum_{i = 1} ^ {k}x_i)的最大值。


    正解确实很难想,先想只有一轮的情况:我们令第(i)种颜色的数额最大的抽奖券为(R_i),最小的为(L_i),那么(x)一定是任意的(frac{n}{2})(R_i)减去另外(frac{n}{2})(L_j)
    我们可以先把(n)(R_i)全部拿出来,然后再用(frac{n}{2})(L_j)替换掉对应的(R_j)。而一次替换对答案的贡献是(-L_j-R_j)。所以把这个贡献从大到小排一个序,取前(frac{n}{2})个,(k=1)的情况就做出来了。


    对于多轮有的情况,我们可以仿照(l=1)的情况:先取(nk)(R_i),然后用(frac{nk}{2})(L_i)替换掉一些(R_i)。不过要多考虑的一点是,(L_i)应该替换掉哪一个(R_i)呢?为了保持最优解,就需要用最小的(L)替换最小的(R),第二小的(L),替换第二小的(R)……因此就可以用一个优先队列来维护:如果一个颜色第(t)小的数额从队首出来了,就把他的贡献加到答案里,并把(t+1)小的数额放进队列里。
    这样进行(frac{nk}{2})次后,就能知道(k)轮选了哪些卡片。


    所以接下来我们要解决这些卡片该怎么分配。
    我们一轮一轮的考虑:记录每一个颜色用了(L_j)的数目(cntL_i),那么取前(frac{n}{2})大的(cntL_i),这些颜色选(L_i),剩下(frac{n}{2})个颜色选(R_i),这样就保证了后面的轮数里不会出现一轮里一种颜色选了多张牌的情况。


    代码写起来不是很难,但一定要保持头脑清醒,否则会忽视很多细节。

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #include<queue>
    using namespace std;
    #define In inline
    typedef long long ll;
    const int maxn = 1505;
    
    typedef vector<int> Ivec;
    extern "C" void allocate_tickets(std::vector<std::vector<int> > s);
    
    int n, m;
    struct Node
    {
    	ll val; int id, col;
    	In bool operator < (const Node& oth)const
    	{
    		return val > oth.val;
    	}
    };
    priority_queue<Node> q;
    int ansL[maxn], cntR[maxn], pos[maxn];
    extern "C" In bool cmp(int a, int b) {return ansL[a] > ansL[b];}
    extern "C" long long find_maximum(int K, vector<Ivec> a)
    {
    	n = a.size(), m = a[0].size();
    	for(int i = 0; i < n; ++i) q.push((Node){a[i][0] + a[i][m - K], 0, i});
    	int cnt = n * K / 2;
    	for(int i = 1; i <= cnt; ++i)
    	{
    		Node tp = q.top(); q.pop();
    		int id = tp.id + 1, col = tp.col;
    		if(id == K) ansL[col] = K;
    		else q.push((Node){a[col][id] + a[col][m - K + id], id, col});
    	}
    	while(!q.empty()) ansL[q.top().col] = q.top().id, q.pop();
    	ll ans = 0;
    	vector<Ivec> g(n, Ivec(m, -1));
    	for(int i = 0; i < n; ++i) pos[i] = i;
    	for(int k = 0; k < K; ++k)
    	{
    		sort(pos, pos + n, cmp);
    //		sort(pos, pos + n, [&](int a, int b) {return ansL[a] > ansL[b];});  //洛谷的交互题评测机不让用lambda表达式…… 
    		for(int i = 0; i < n; ++i)
    		{
    			int p = pos[i];
    			if(i < (n >> 1)) g[p][--ansL[p]] = k, ans -= a[p][ansL[p]];
    			else g[p][m - (++cntR[p])] = k, ans += a[p][m - cntR[p]];
    		}
    	}
    	allocate_tickets(g);
    	return ans;
    } 
    
  • 相关阅读:
    C3P0的详细配置说明
    关于commons-fileupload组件上传文件中文名乱码问题
    手写JDBC
    使用try-with-resource遇到的问题
    Java基础学习总结——Java对象的序列化和反序列化
    IDEA查看第三方jar包的源代码时出现Decompiled.class file, bytecode version:52.0 (Java 8)的解决方案
    软件工程课程周进度报告 第六周
    地铁合作的第二周
    第六周进度总结
    地铁合作的第一周
  • 原文地址:https://www.cnblogs.com/mrclr/p/14120381.html
Copyright © 2011-2022 走看看