D. Smooth Array
根据题意,显然是长度为k的循环节,所以按数组下标对k的余数进行分组
问题转换为:k组元素,每组选择一个要变换为的数值w,其价值为本组元素与w相 同的个数,且k组数值w的和为S.
最终使(N − 总价值)最小,即修改次数最 少。
分K组做一下背包。c[i]为该组i出现的次数。f[i]为体积为i时的最大价值。g[i]为上一组元素,到i这个体积的最大f[]值,在本组背包更新后,用g更新f,因为相当于本组一点贡献都没有,f[i]都一定能打到g[i]的价值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=5e3+7;
int a[maxn],f[maxn],c[maxn],g[maxn];
int main()
{
int n,k,s;
scanf("%d%d%d",&n,&k,&s);
for(int i=0;i<n;i++) scanf("%d",&a[i]);
memset(f,-0x3f,sizeof(f));
f[0]=0;
for(int i=0;i<k;i++){
vector<int>tmp;
memset(c,0,sizeof(c));
memset(g,0,sizeof(g));
for(int j=i;j<n;j+=k){
if(c[a[j]]==0) tmp.push_back(a[j]);
c[a[j]]++;
}
for(int j=0;j<=s;j++) g[j]=max((j?g[j-1]:0),f[j]);
for(int j=s;j>=0;j--){
f[j]+=c[0];
for(auto it:tmp){
if(it&&j>=it){
f[j]=max(f[j],f[j-it]+c[it]);
}
}
f[j]=max(f[j],g[j]);
}
}
printf("%d\n",n-f[s]);
return 0;
}
E
F. Atlantis
题意:海平面每秒上涨1m,有n个地点,每个地点有t往返时间,h海拔高度,在来回过程中那个地点必须一直保持在海平面上。求最多能去几个地点
题解:
因为海拔越低越早被淹没,所以相同时间下,海拔低的地点应该优先去。
按海拔高低排序后,维护往返时间从大到小的任务优先队列,sum为完成已经队列里的人物的总时间。
若该地点需要的往返时间+sum<=海拔,说明该任务可做,直接放进队列;
否则,比较队列里最大的时间,如果此时任务的时间小于最大时间,替换任务。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
priority_queue<ll>q;
struct node{
int t,h;
bool operator <(const node &b){
return h<b.h;
}
}a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].t,&a[i].h);
sort(a+1,a+1+n);
ll sum=0;
for(int i=1;i<=n;i++){
if(sum+a[i].t<=a[i].h){
q.push(a[i].t);
sum+=a[i].t;
}
else{
if(!q.empty()&&q.top()>a[i].t){
sum-=q.top();
q.pop();
q.push(a[i].t);
sum+=a[i].t;
}
}
}
printf("%d\n",q.size());
return 0;
}
来源:CSDN
作者:knopfler
链接:https://blog.csdn.net/qq_39898877/article/details/104598304