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 ° = 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 最大密度子图
题意
给定一个无向图,给定边权和点权,选择若干的点,使得他们的边权和-点权和最大