codeforces contest1082

C 维护前缀和

题意

每一个id给一个权值序列,从每个id选出数量相同的权值,对他们进行求和,使得他们的和最大

题解

注意负数对结果没有贡献,直接跳过。

当时写的比较挫,连排序都写错了!cf的编译器比较的严谨,虽然本地的编译器过了样例,但实际上是有问题的。结果就是交上去疯狂RE。

题解就直接看代码,比较的直观

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5+10;
int n, m, k;
int a[maxn];
struct Node{
    int id, val;
    bool operator < (const Node &b) const{
        if(id!=b.id) return id<b.id;
        else return val>b.val;
    }
}node[maxn];

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>m;
    int u, v;
    for(int i=1; i<=n; i++){
        cin>>node[i].id>>node[i].val;
    }
    sort(node+1, node+1+n);
    int pre=-1;
    int c;
    int sum = 0;
    int ans = -1e9-10;
    for(int i=1; i<=n; i++){
        if(node[i].id!=pre){
            pre = node[i].id, c=0, sum = 0;
        }
        c++;
        sum +=node[i].val;
        if(sum>0) {
            a[c]+=sum;
        }
        ans = max(ans, a[c]);
    }
    if(ans == -1e9-10) cout<<0<<endl;
    else  cout<<ans<<endl;

    return 0;
}

D 构造题

题意

给n个点,每个点限制一个度数(a_i),你要构造一个无向图,使得每个点的度数不超过限制,并且最长链最长。

题解

度数大于等于2的点先构成一个最长链,然后度数为1的先加在两头(否则会使答案错误),之后的点在中间插就行了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)

const int inf = 0x3f3f3f3f;
const int maxn = 500+10;

int readint()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int n, m;
int a[maxn];
vector<int> lone;
vector<int> two;

int main()
{
    ios::sync_with_stdio(false);
    cin>>n;
    int tot = 0;
    int one = 0;
    int sum = 0;
    int u, v;
    for(int i=1; i<=n; i++) {
        cin>>a[i];
        if(a[i]>1) tot += 1, two.push_back(i);
        else one+=1, lone.push_back(i);
        sum += a[i];
    }
    if(sum<2*n-2){
        cout<<"NO"<<endl;
        return 0;
    }
    {
        if(one>=2)
            cout<<"YES "<<tot+1<<endl<<n-1<<endl;
        else cout<<"YES "<<tot-1+one<<endl<<n-1<<endl;
        for(int i=0; i<two.size(); i++){
            if(i+1<two.size()){
                u = two[i], v = two[i+1];
                a[u]--, a[v]--;
                cout<<u<<" "<<v<<endl;
            }
        }
        int idx = 0;
        if(lone.size()>=2){
            u=lone[0], v=lone[1];
            cout<<u<<" "<<two[0]<<endl;
            a[two[0]]--;
            cout<<v<<" "<<two[two.size()-1]<<endl;
            a[two[two.size()-1]]--;
            idx=2;
        }
        for(int i=0; i<two.size(); i++){
            int &deg = a[two[i]];
            if(idx >= int(lone.size())) break;
            for(int j=idx; j<min(int(lone.size()), deg+idx); j++){
                cout<<lone[j]<<" "<<two[i]<<endl;
            }
            idx+=deg;
            deg = 0;
        }
    }
    return 0;
}

E Increasing Frequency--思维+贪心

题意

给一个长度为n的序列,并且确定一个数c。(你可以任选一个区间[l, r], 对该区间+k,k可以为负数),使得最后的n个数中,等于c的数字的个数最多。问最多有多少个这样的数?

题解

Let $ cnt(l,r,x) $ be a number of occurrences of number x in subsegment$ [l,r] $.

The given task is equivalent to choosing ([l,r]) and value d, such that $ans=cnt(1,l−1,c)+cnt(l,r,d)+cnt(r+1,n,c) $is maximum possible. But with some transformations (ans=cnt(1,n,c)+(cnt(l,r,d)−cnt(l,r,c))), so we need to maximize (cnt(l,r,d)−cnt(l,r,c)).

代码的精髓就是求解maximize(cnt(l, r, d)-cnt(l, r, c))

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<cmath>
#include<map>
#include<stack>
#include<set>
#include<bitset>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
#define pb(x) push_back(x)
#define cls(x, val) memset(x, val, sizeof(x))
#define fi first
#define se second
#define mp(x, y) make_pair(x, y)
#define inc(i, l, r) for(int i=l; i<=r; i++)

const int inf = 0x3f3f3f3f;
const int maxn = 5e5+10;

int readint()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

int cnt[maxn];
int n, c;
int mi[maxn];

int main()
{
    ios::sync_with_stdio(false);
    cin>>n>>c;
    int temp;
    int ans = 0;
    for(int i=1; i<=n; i++){
        cin>>temp;
        mi[temp] = min(mi[temp], cnt[temp]-cnt[c]);
        cnt[temp]++;
        ans = max(ans, cnt[temp]-cnt[c]-mi[temp]);
    }
    cout<<ans+cnt[c]<<endl;

    return 0;
}

F trie+dp

G 最大密度子图

题意

给定一个无向图,给定边权和点权,选择若干的点,使得他们的边权和-点权和最大

题解

原文地址:https://www.cnblogs.com/babydragon/p/10042557.html