【Educational Codeforces Round 108 (Rated for Div. 2)】-C.Berland Regional-暴力优化(鸽巢原理)+前缀和

题目:
【Educational Codeforces Round 108 (Rated for Div. 2)】-C.Berland Regional-暴力优化(鸽巢原理)+前缀和_第1张图片
思路:
比赛前再睡觉我是狗
这题没想到优化是在这里
对存入的学校离散化一下(防止MLE)
然后对每个学校的学生得分进行降序排序
再对所有学校的学生人数进行降序排序
统计一下每个学校的得分前缀和

然后关键优化时间的思想:
如果存在一个人数非常多的学校,那么别的学校的总人数都很少

双重循环统计在每个分块长度时所有学校的总分
如果有学校的总人数不够分块
那么直接跳过,开始下一个长度的分块计算
所以看似双重循环,但时间大大缩短,有很多用不到的都没统计了

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#define G 10.0
#define LNF 1e18
#define eps 1e-6
#define PI acos(-1.0)
#define ll long long
#define INF 0x7FFFFFFF
#define Regal exit(0)
#define Chivas int main()
#define pb(x) push_back(x)
#define SP system("pause")
#define ull unsigned long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define IOS ios::sync_with_stdio(false)
#define mm(a, b) memset(a, b, sizeof(a))
#define each_cass(cass) for (cin >> cass; cass; cass--)
#define test(a) cout << "---------" << a << "---------" << '\n'

using namespace std;

bool cmp(vector<ll> a, vector<ll> b){
     return a.size() > b.size();}

inline void solve()
{
     
    ll n;
    cin >> n;
    unordered_map<ll, ll> mp;//记录出现过这个学校编号没
    ll u_cnt = 0;
    vector<ll> a;
    for (ll i = 0, x; i < n; i++){
     
        scanf("%lld", &x);
        if (!mp[x]){
     
            mp[x] = ++u_cnt;//离散化建立编号与离散结果的映射
        }
        a.push_back(x);
    }
    vector<ll> uni[u_cnt + 10];
    for (ll i = 0, x; i < n; i++){
     
        scanf("%lld", &x);
        uni[mp[a[i]]].push_back(x);
    }
    for (ll i = 1; i <= u_cnt; i++)
        sort(uni[i].begin(), uni[i].end(), greater<ll>());
    sort(uni + 1, uni + u_cnt + 1, cmp);//从大到小排序可以跳过后面的

    vector<vector<ll> > sumfro(u_cnt + 10);//记录前缀和

    for (ll i = 1; i <= u_cnt; i++){
     
        ll len = uni[i].size();
        for (ll j = 0; j < len; j++){
     
            if (j == 0)
                sumfro[i].push_back(uni[i][j]);
            else
                sumfro[i].push_back(sumfro[i].back() + uni[i][j]);
        }
    }

    ll sum[n + 10] = {
     0};
    for (int i = 1; i <= n; i++)
    {
     
        for (int j = 1; j <= u_cnt; j++)
        {
     
            if ((uni[j].size()) / i > 0)
                sum[i] += sumfro[j][uni[j].size() / i * i - 1];
            else//精华:卡我所在,小于i的都不算
                break;
        }
    }
    for (int i = 1; i <= n; i++)
        printf("%lld ", sum[i]);
    printf("\n");
}

Chivas
{
     
    ll cass;
    scanf("%lld", &cass);
    while (cass--)
    {
     
        solve();
    }
    Regal;
}

你可能感兴趣的:(#,CodeForces)