标签:mem 并且 stdout cto space cstring 之间 int inline
等比数列的性质,前面的i
项的和,不会超过第i+1
项
有若干个区间,要求每一个点被区间覆盖的次数不能超过k个。问移除的最少的区间的数目。
贪心:
若某个点被覆盖了k次以上,那么肯定是移除这些区间里面右端点最右的点的区间。
时间复杂度要求是\(O(nlog(n))\)
模拟就好了
#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 = 2e5+10;
int l[maxn], r[maxn];
int n, k;
vector<int> node[maxn];
set<pii> s;
int main(){
ios::sync_with_stdio(false);
cin>>n>>k;
for(int i=1; i<=n; i++){
cin>>l[i]>>r[i];
node[l[i]].push_back(i);
node[r[i]+1].push_back(-i);
}
vector<int> ans;
for(int i=1; i<=2e5; i++){
for(int j=0; j<node[i].size(); j++){
int u = node[i][j];
if(u>0){
s.insert(mp(r[u], u));
}
else s.erase(mp(r[-u], -u));
}
while(s.size()>k){
set<pii>::iterator it = s.end();
--it;
ans.push_back(it->se);
s.erase(*it);
}
}
cout<<ans.size()<<endl;
for(int i=0; i<ans.size(); i++){
cout<<abs(ans[i])<<" ";
}
cout<<endl;
return 0;
}
简单dp
题目:
要求一个点的集合,使得他们之间的任意两点之间的距离大于k,并且这个集合的点的权重和最大
树形dp
学习了一种很trick的写法,不具有普遍性
#include <bits/stdc++.h>
using namespace std;
const int maxn = 200 + 10;
vector<int> G[maxn];
int n, k, m;
int a[maxn], vis[maxn];
void dfs(int u, int fa, int d){
if(d > k) return ;
a[u] -= m;
for(int &v : G[u]) if(v != fa) dfs(v, u, d + 1);
}
int main(){
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; i++) scanf("%d", a + i);
for(int i = 1; i < n; i++){
int u, v;
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
queue<int> q;
vector<int> b;
q.push(1); vis[1] = 1;
while(!q.empty()){
int u = q.front(); q.pop();
b.push_back(u);
for(int &v : G[u]){
if(!vis[v]){
q.push(v);
vis[v] = 1;
}
}
}
int ans = 0;
for(int i = b.size() - 1; i >= 0; i--){
//这里写的很trick, 从叶子节点开始取。若上面有更好的选择,那么相当于就叶子的贡献转移到上面了。
m = a[b[i]];
if(m < 0) continue;
ans += m;
dfs(b[i], 0, 0);
}
printf("%d\n", ans);
return 0;
}
树形dp的写法有点像另外的一个题目:
给一个树形的结构,然后任意一个节点到关键节点的距离不能超过k。
问最小的关键节点的数目。
#include <bits/stdc++.h>
using namespace std;
const int N = 210;
int n, k;
vector<int> a;
vector<vector<int>> g, dp;
void dfs(int v, int p) {
dp[v][0] = a[v];
for (auto to : g[v]) {
if (to != p) dfs(to, v);
}
for (int dep = 0; dep < N; ++dep) {
if (dep == 0) {
for (auto to : g[v]) {
if (to == p) continue;
dp[v][dep] += dp[to][max(0, k - dep - 1)];
}
} else {
for (auto to : g[v]) {
if (to == p) continue;
int cur = dp[to][dep - 1];
for (auto other : g[v]) {
if (other == p || other == to) continue;
cur += dp[other][max(dep - 1, k - dep - 1)];
}
dp[v][dep] = max(dp[v][dep], cur);
}
}
}
for (int dep = N - 1; dep > 0; --dep) {
dp[v][dep - 1] = max(dp[v][dep - 1], dp[v][dep]);
}
}
int main() {
#ifdef _DEBUG
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
cin >> n >> k;
++k;
a = vector<int>(n);
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
g = vector<vector<int>>(n);
for (int i = 0; i < n - 1; ++i) {
int x, y;
cin >> x >> y;
--x, --y;
g[x].push_back(y);
g[y].push_back(x);
}
dp = vector<vector<int>>(n, vector<int>(N));
dfs(0, -1);
cout << dp[0][0] << endl;
return 0;
}
标签:mem 并且 stdout cto space cstring 之间 int inline
原文地址:https://www.cnblogs.com/babydragon/p/11725009.html