Codeforces 723c [贪心][乱搞]

/*
不要低头,不要放弃,不要气馁,不要慌张。
题意:
给一个n和m。
第二行给n个数。
每次操作可以把n个数中的任何一个数替代为别的数,问最少的操作次数使得1.2.3.4.5...m中的数出现的次数的最小值尽可能大。
输出这个数,输出最少操作次数,输出替换后的数组。
思路:
1.显然,最小值尽可能大,这个值是可以确定的,即n/m;
2.还有,为使得操作次数最少,我们发现最多有n%m个没有贡献的无关值无需更改...
3.这题实际上可以n^2复杂度,因为n只有2000.但是本渣作死,写了nloglog的复杂度...
n^2复杂度的话循环检查就好...
我是用一个map<int,multiset<int> >将数字的位置记录下来...然后种种... 

坑:
if else if else这种逻辑写崩了==仍然很弱的我
逻辑逻辑逻辑

*/

#include<bits/stdc++.h>
using namespace std;
int jilu[2050],all[2050];
map<int,multiset<int> >mp;
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%d",jilu+i);
        all[i]=jilu[i];
        mp[jilu[i]].insert(i);
    }
    int k=n/m;
    int w=n%m;
    map<int,multiset<int> >::iterator it;
    multiset<int>cun;
    multiset<int>que;
    for(it=mp.begin();it!=mp.end();it++){
        if(it->first <= m){
            while(it->second.size()<k){
                if(cun.size()){
                    int ss=*cun.begin();
                    cun.erase(cun.begin());
                    jilu[ss]=it->first;
                    it->second.insert(ss);
                }
                else{
                    que.insert(it->first);
                    it->second.insert(0);
                }
            }
            while(it->second.size() > k){
                if(w>0){
                    w--;
                    it->second.erase(it->second.begin());
                }
                else if(que.size()){
                    int ss=*que.begin();
                    que.erase(que.begin());
                    int pos=*(it->second.begin());
                    it->second.erase(it->second.begin());
                    jilu[pos]=ss;
                }
                else{
                    int pos=*(it->second.begin());
                    it->second.erase(it->second.begin());
                    cun.insert(pos);
                }
            }
        }
        else{
            while(it->second.size() > 0){
                if(w>0){
                    w--;
                    it->second.erase(it->second.begin());
                }
                else if(que.size()){
                    int ss=*que.begin();
                    que.erase(que.begin());
                    int pos=*(it->second.begin());
                    it->second.erase(it->second.begin());
                    jilu[pos]=ss;
                }
                else{
                    int pos=*(it->second.begin());
                    it->second.erase(it->second.begin());
                    cun.insert(pos);
                }
            }
        }
    }
    for(int i=1;i<=m;i++){
        while(mp[i].size()<k){
            int ss=*cun.begin();
            cun.erase(cun.begin());
            jilu[ss]=i;
            mp[i].insert(ss);
        }
    }
    while(que.size()){
        int pos=*cun.begin();
        int ss=*que.begin();
        cun.erase(cun.begin());
        que.erase(que.begin());
        jilu[pos]=ss;
    }
    int num=0;
    for(int i=1;i<=n;i++){
        if(jilu[i]!=all[i])num++;
    }
    printf("%d %d\n",k,num);
    for(int i=1;i<=n;i++){
        printf("%d ",jilu[i]);
    }
}
时间: 2024-10-23 18:52:11

Codeforces 723c [贪心][乱搞]的相关文章

[CF825D] Suitable Replacement (贪心乱搞)

题目链接:http://codeforces.com/problemset/problem/825/D 题意:给两个字符串s t,s中有一些问号.现在问号可以替换为任意字符,s字符串可以任意换位置,希望让t在s中出现次数最多. 统计s中各个字符出现次数,一直扫t,用s中与t相同字符抵消,不能抵消就用问号抵消.直到问号没有为止. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef pair<int, int> p

Codeforces 732e [贪心][stl乱搞]

/* 不要低头,不要放弃,不要气馁,不要慌张 题意: 给n个插座,m个电脑.每个插座都有一个电压,每个电脑都有需求电压. 每个插座可以接若干变压器,每个变压器可以使得电压变为x/2上取整. 有无限个变压器供应. 问最多能使得多少个插座与电脑匹配,使得电压一致. 如果有多种方案,输出需要变压器总数最小的那种. 输出匹配数量 输出每个插座需要接多少个变压器.输出每台电脑匹配哪个插座. 思路: 贪心 乱搞 先从小到大将插座排序,然后从地第一个插座开始,不断除以2上取整.不断找是否可以匹配.找到匹配就停

Codeforces Amr and Chemistry(数学+乱搞)

题意:给n个数,每个数每次可以乘二或除以二(向下取整相当于左移或右移),问最少经过多少次操作可以使这n个数变相等. 思路:首先考虑每个数的可能取值,将一个数表示成s*2^k的形式,s是奇数. 那么这个数的所有可能取值为s'*2^x,(s'=s/2,(s/2)/2,.....)且s'*2^x<=100000 因为这题数据范围不大,而且每个值可能的取值不多最多几百个,所以记录1到100000每个值可能被取到的次数以及总操作数,最后从1遍历到100000取最小的ans即可 ps:个人赛这道题做了一下午

codeforces 653C C. Bear and Up-Down(乱搞题)

题目链接: C. Bear and Up-Down time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output The life goes up and down, just like nice sequences. Sequence t1, t2, ..., tn is called nice if the following two

Codeforces 484(#276 Div 1) A Bits 乱搞

题意:给你一个非负整数范围,求其中二进制中 1 最多且数字最小的数 解题思路:乱搞,找到两个数第一个不匹配的位数,将后面的位都赋值为1(如果右端点这位本身就是1,则从这一位开始), 解题代码: 1 // Author: darkdream 2 // Created Time: 2014年11月06日 星期四 00时24分10秒 3 4 #include<vector> 5 #include<list> 6 #include<map> 7 #include<set&

Codeforces 1077E (二分乱搞或者dp)

题意:给你一个数组,可以从中选区若干种元素,但每种元素选区的个数前一种必须是后一种的2倍,选区的任意2种元素不能相同,问可以选取最多的元素个数是多少? 思路1(乱搞):记录一下每种元素的个数,然后暴力枚举最少的元素个数,计算符合题意的最优情况. 代码: #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> #include<map> #include<s

Codeforces 1186F - Vus the Cossack and a Graph 模拟乱搞/欧拉回路

题意:给你一张无向图,要求对这张图进行删边操作,要求删边之后的图的总边数 >= ceil((n + m) / 2), 每个点的度数 >= ceil(deg[i] / 2).(deg[i]是原图中i的度数) 思路1:模拟 + 乱搞 直接暴力删就行了,读入边之后随机打乱一下就很难被hack了. 代码: #include <bits/stdc++.h> #define LL long long #define INF 0x3f3f3f3f #define db double #defin

CodeForces - 1228D (暴力+思维+乱搞)

题意 https://vjudge.net/problem/CodeForces-1228D 有一个n个顶点m条边的无向图,在一对顶点中最多有一条边. 设v1,v2是两个不相交的非空子集,当满足以下条件时f(v1,v2)为真 v1中的点之间不存在边 v2中的点之间不存在边 对于在v1v2中的每一对顶点,x在v1中,y在v2中,xy之间有边 所有点集不为空,且不相交,是否有v1,v2,v3使得f(v1,v2).f(v2,v3).f(v3,v1)均为真 如果有输出每个点所在的点集(1,2,3),否则

UVA 11853 [dfs乱搞]

/* 大连热身E题 不要低头,不要放弃,不要气馁,不要慌张 题意: 在1000×1000的格子内有很多个炮弹中心,半径给定. 为某人能否从西部边界出发,从东部边界走出. 不能输出不能,能的话输出最北边的入口和出口的坐标. 思路: dfs乱搞题.把炮弹辐射范围连在一起的炮弹看作一个整体,记录下它围起来的边界区域. 然后找到最北边的输出. */ #include<bits/stdc++.h> using namespace std; double x[1005],y[1005],r[1005];