codeforces 1315D Recommendations

codeforces 1315D Recommendations

题意:

​ 每个点两个属性,\(a[ i ],t[ i ]\)(给该点\(a[ i ] +1\)的消耗),现在要求\(a_i\)各不相同,问你最小花费

题解:

​ 按照时间从大到小,序号从小到大,用并查集维护祖先,用来表示该点最终需要加到多大的值,并通过祖先计算自身需要进行几次操作,答案就加上几次相应的时间。

​ 一开始默认\(fa[i]\)都为\(0\),意思是\(find(i)\)都为自己本身,因为每个数字最多出现一次,那么当我们遍历到一个数字\(x\)的时候,就说明这个\(x\)之后不能再出现了,再次出现的\(x\)必须变成\(x+1\),同理出现了\(x+1\)之后就必须变成\(x+2\),这就要\(unite(x,x+1)\),(不能\(unite(x+1,x)\),因为祖先肯定比\(x\)大)这一步操作结束之后,相当于是处理出了这个数字在最终需要变为的数字。两者相减即为操作次数,乘上时间就是对答案的贡献,由于处理是从前往后的,所以对于同一个\(x\),时间小的肯定放在后面(贪心思想)。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pll pair<ll, ll> 
const int maxn = 2e5 + 10;
ll a[maxn], t[maxn];
map<ll, ll> fa;
pll q[maxn];
bool cmp(pll &a, pll &b){
    if(a.second == b.second){
        return a.first < b.first;
    }
    return a.second > b.second;
}

ll find(ll x){
    return fa[x] == 0 ? x : fa[x] = find(fa[x]);
}
void unit(ll x, ll y){
    x = find(x), y = find(y);
    if(x != y)
        fa[x] = y;
}
int main(){
    int n;

    cin >> n;
    for (int i = 0; i<n; i++){
        cin >> a[i];
    }
    for (int i = 0; i<n; i++){
        cin >> t[i];
        q[i].first = a[i];
        q[i].second = t[i];
    }
    sort(q, q + n, cmp);
    /*for (int i = 0; i < n; i++){
        cout << q[i].first << " " << q[i].second << endl;
    }*/
    ll ans = 0;
    for (int i = 0; i < n; i++){
        ll x = find(q[i].first);
        ans += (x - q[i].first) * q[i].second;
        unit(x, x + 1);
    }
    cout << ans << endl;
    return 0;
}
posted @ 2020-02-29 09:30  Frnas  阅读(111)  评论(0编辑  收藏  举报
Language: HTML