Codeforces Round 982 (Div. 2) A-D个人题解

前言

本场传送门:https://codeforces.com/contest/2027
比赛只写出来了A,B 有点惭愧

A.Rectangle Arrangement

\(W=max(w_i)\)
\(H=max(h_i)\)
周长最大值\(=2\cdot(W+H)\)

B.Stalin Sort

vulnerable array性质: 最大值在最左侧
\(n\) 只有 \(2000\),可以暴力枚举,设第 \(i\) 位为这个最大值
$ [1,i-1] $ 的所有数都删掉
$ [i+1,n] $ 的数只删掉严格大于 \(a[i]\)
统计删掉的数的个数,求最小值

C.Add Zeros

思路

如果数组后加了 \(k\) 个0,那么 \(a_i\) 能被选上的值就是 \(n+k-i+1\)
\(u_i=a_i-(n-i+1)\)\(u_i\) 代表的就是总共需要加多少0能选上这个数
\(v_i=a_i-(n-i+1)+i-1\)\(v_i\) 代表的就是进入 \(u_i\) 后末尾的0总数
\(u_i\) 指向 \(v_i\) 建图(若 \(u\)\(v\) 小于0则放弃这条边)
然后从0进入这张图,能到达的最大的点加上n(就是最多增加的0数)就是答案
求这个最大点我用的是记忆化dfs,开个map保存点 \(u\) 是否走过
不过貌似bfs会更好一点(?),当然也要开个map记录该点是否被走过

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
ll n,x,ans;
map<ll,vector<ll> > mp;
map<ll,bool> vis;
void dfs(ll x);
void solve();
void dfs(ll x){
ans=max(x,ans);
vis[x]=true;
for(ll u:mp[x]){
if(!vis[u]){
dfs(u);
}
}
}
void solve(){
cin>>n;
mp.clear();
vis.clear();
for(ll i=1;i<=n;i++){
cin>>x;
ll u=x-n-1+i;
ll v=x-n-1+i+i-1;
if(u<0 || v<0){
continue;
}
vis[u]=false;
vis[v]=false;
mp[u].push_back(v);
}
ans=0;
dfs(0);
cout<<n+ans<<'\n';
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
ll t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}

D1. The Endspeaker (Easy Version)

思路

使用动态规划
\(dp[i][j]\)表示当前在 \(a_i\) 且在 \(b_j\) 的最小代价。
因为一次吸收前缀产生\(m-k\)的代价是固定的,所以尽可能在\(a\)数组里多取
最终答案就是 \(\mathop{min}\limits_{1 \leq j \leq m}( dp[n][j] )\)

对于type1 \(dp[i][j+1]=min(dp[i][j] , dp[i][j+1] )\)
对于type2 \(dp[x][j]=min(dp[i][j]+m-j , dp[x][j] )\)
其中 \(x\)\(sum_x\) 满足小于等于 \(sum_i+b_j\) 最大的下标

代码

#include<bits/stdc++.h>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
ll n,m;
void solve();
void solve(){
cin>>n>>m;
vector<ll> a(n+1,0),b(m+1,0),sum(n+1,0);
ll Max=0;
for(ll i=1;i<=n;i++){
cin>>a[i];
Max=max(Max,a[i]);
sum[i]=sum[i-1]+a[i];
}
for(ll i=1;i<=m;i++){
cin>>b[i];
}
if(Max>b[1]){ //非法条件:a最大值比b最大值比还大
cout<<-1<<'\n';
return ;
}
vector<vector<ll> > dp; //直接设dp[300005][300005]会炸,所以用vector
dp.resize(n+1);
for(ll i=0;i<=n;i++){
dp[i].resize(m+1);
}
for(ll i=0;i<=m;i++){ //初始化
dp[0][i]=0LL;
}
for(ll i=1;i<=n;i++){ //最小值只能从i=0开始转移,所以i=0之外的都要设成inf
for(ll j=0;j<=m;j++){
dp[i][j]=inf;
}
}
for(ll i=0;i<=n;i++){
for(ll j=1;j<=m;j++){
dp[i][j]=min(dp[i][j-1],dp[i][j]);
ll pos=upper_bound(sum.begin()+i,sum.end(),b[j]+sum[i])-sum.begin(); //找x就是找第一个大于b_j+sum_i的前一个下标
pos--;
dp[pos][j]=min(dp[pos][j],dp[i][j]+m-j);
}
}
ll Min=inf;
for(ll i=1;i<=m;i++){
Min=min(Min,dp[n][i]);
}
cout<<Min<<'\n';
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
ll t=1;
cin>>t;
while(t--){
solve();
}
return 0;
}
posted @   Gusare  阅读(71)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示