当前位置: 首页 > news >正文

Codeforces Round 1037 (Div. 3)(A,B,C,D,E,F,G1)

Codeforces Round 1037 (Div. 3)

A

题意

给定x,求最小非负整数y满足y和x至少有一个数字相同

思路

找x十进制下最小的数字即可

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){int n;cin>>n;int res=9;while(n){res=min(n%10,res);n/=10;}cout<<res<<"\n";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}

B

题意

给出了n天的天气为a[i],每次爬山峰需要恰好连续的k天(这k天必须保证天晴),并且每爬完一个山峰至少休息一天,问最多爬几个山峰

思路

很明显我们可以采用贪心的思路,即只要连续k天为天晴我们就爬山,直接模拟即可

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){int n,k;cin>>n>>k;vector<int>a(n+1,0);int now=0;int res=0;for(int i=1;i<=n;i++)cin>>a[i];for(int i=1;i<=n;i++){if(a[i]==0){now++;if(now==k){i++;res++;now=0;}}else{now=0;}}cout<<res<<"\n";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}

C

题意

每一秒水位都会上涨1,现在你站在h[k]的位置,从i位置传送到j位置需要|h[i]-h[j]|秒,并且在这期间一直处在i位置,问能否在水位高于自己位置之前到达最高点

思路

因为传送之和高度有关,与相对位置无关,为了方便我们可以直接对n个位置进行高度排序

假设我们现在从i位置传送j位置,因为每次在传送的过程中水也会同步上涨,所以每一步传送完之后和在传送开始之前与水面的相对高度是不变的,那么对于我们来说只要在等待的这|h[i]-h[j]|秒没有被淹没即可,换句话说要满足|h[j]-h[i]|<=h[i]-(传送前的水高)

既然这样我们就可以考虑贪心,每次往上一步一步传送,一定能使得最后的结果不劣,同时我们考虑到当前位置-传送前的水高 这个差值是保持不变的,因为一开始的水高为0,当前所在的位置高度为h[k],所以这个值实际上就是h[k],所以每次传送前判定是否满足h[j]-h[i]<=h[k]即可

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){int n,k;cin>>n>>k;vector<int>a(n+1,0);for(int i=1;i<=n;i++)cin>>a[i];int gdc=a[k];sort(a.begin()+1,a.end());for(int i=1;i<=n;i++){if(a[i]<=gdc)continue;if(a[i]-a[i-1]>gdc){cout<<"NO\n";return;}}cout<<"YES\n";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}

D

题意

有n个赌场,每个赌场有l[i],r[i],real[i],代表只有钱在l[i]~r[i]之间才能进入这个赌场,并且出赌场的钱后手上的钱为real[i],每个赌场只能进入一次,现在问怎么安排进入赌场的顺序(不一定要全部进入)使得最后能获得最多的钱

思路

考虑贪心,我们可以按照进入赌场的门槛(l[])从小到大对赌场进行排序,只要能进入我们就考虑出来的real[i]是否大于当前的钱数,如果real[i]大于手上的钱则跟更新,否则不更新,这样能保证钱数一直增加,并且能考虑到所有能进入的赌场使得最后的结果不劣。

代码

//左端点从小到大
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){int n,k;cin>>n>>k;vector<pair<pair<int,int>,int>>a(n+1);for(int i=1;i<=n;i++)cin>>a[i].first.first>>a[i].first.second>>a[i].second;sort(a.begin()+1,a.end());int now=k;for(int i=1;i<=n;i++){if(a[i].first.first>now)break;if(now>a[i].first.second)continue;now=max(now,a[i].second);}cout<<now<<"\n";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}

E

题意

给定两个数组代表前缀gcd和后缀gcd,问是否存在一个合法数组满足前缀和后缀的gcd为给定的这两个数组。

思路

思路1:对于位置i来说,因为p[i]是前缀gcd,s[i]是后缀gcd,所以a[i]必须至少是p[i]的倍数,同时也是s[i]的倍数,所以a[i]至少是lcm(s[i],p[i])的倍数,然后我们只需从前往后,从后往前对a[i]数组进行验证即可

思路2:先判断前缀和后缀两个数组是否都满足相邻两个元素一定是满足整除关系,然后在判断对于所有的gcd(pre[i],suf[i+1])是否等于全局gcd (pre[n]和suf[1])

代码

//思路2的代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
void solve(){int n;cin>>n;vector<int>pre(n+1,0),suf(n+1,0);for(int i=1;i<=n;i++)cin>>pre[i];for(int i=1;i<=n;i++)cin>>suf[i];for(int i=1;i+1<=n;i++){if(pre[i]%pre[i+1]!=0){cout<<"NO\n";return;}}for(int i=n-1;i>=1;i--){if(suf[i+1]%suf[i]!=0){cout<<"NO\n";return;}}if(pre[n]!=suf[1]){cout<<"NO\n";return;}if(suf[n]%pre[n]!=0||pre[1]%suf[1]!=0){cout<<"NO\n";return;}for(int i=1;i+1<=n;i++){if(__gcd(pre[i],suf[i+1])!=pre[n]){cout<<"NO\n";return;}}cout<<"YES\n";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}

F

题意

树上有n个节点,每个节点有一种颜色a[i],现在有n-1条边,每条边的成本为如果顶点ui和顶点vi成本相同则为0,否则为ci

现在给出q个查询,每个查询修改一个顶点的颜色为x,修改操作是永久的,问每次修改完以后树上所有的边权和为多少

思路

最朴素的思想,既然每次只会修改一个点,那么我们每次在查询的时候只需要修改与这个点有关的边即可,那么又有一个问题,如果这个节点连出去的边有很多(菊花图),那么这样的复杂度会为O(n*q)(即每次遍历的点都具有n-1条边)很明显这样是会被卡的。

但同时我们发现这样的顶点实际上很少,因为不可能每个点都有n-1条连边,考虑根号分治优化复杂度。

那么我们要如何分治呢?

首先需要将节点分为两类,一类是度很小的节点,一类是度很大的节点

(1)如果节点的度很小,我们可以采取直接遍历边修改的方式(朴素做法)

(2)如果节点的度很大,我们考虑用数据结构去维护与这个节点连边的顶点的节点颜色有多少种,在修改的时候只要判断修改后的颜色有多少条相同的即可,注意节点度大的之间也需要记录更新

(然后发现以上的分治方法应该是被赛后的数据卡了…)

我们考虑其他方法,因为树有特殊的性质,考虑先预处理所有节点的儿子节点的信息(不同颜色的顶点的连边的价值和为多少),每次更新时只需要考虑儿子节点和父节点,同时当前节点更新的时候需要更新父节点的信息(因为当前节点与父亲节点的连边信息是存储在父节点中),因为一个节点有且只有一个父亲节点(根节点除外),所以在O(1)时间内就可以实现当前节点父节点的信息更新。

因为只维护了每个节点的“子节点颜色和其连边代价之和”的信息,而没有维护所有颜色的全局统计,一条边的信息记录在父节点当中,所以每条边都只在map中记录了一遍,空间是有限的(即为边的数量),每次查询的复杂度为log,总复杂度为(qlogn)能通过本题。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int mxn=1e6+5;
vector<pair<int,int>>edge[mxn];
int color[mxn];
int pa[mxn];
int ans;
map<int,int>all[mxn];
int fs[mxn];//当前节点与父节点的连边的值
void dfs(int u,int fa){pa[u]=fa;for(auto [v,w]:edge[u]){if(v==fa)continue;ans+=(color[u]!=color[v])*w;fs[v]=w;//记录当前节点和父节点之间的边all[u][color[v]]+=w;dfs(v,u);}
}
void solve(){int n,q;cin>>n>>q;ans=0;//当前答案for(int i=1;i<=n;i++)edge[i].clear(),pa[i]=0,all[i].clear(),fs[i]=0;for(int i=1;i<=n;i++)cin>>color[i];for(int i=1;i<n;i++){int u,v,w;cin>>u>>v>>w;edge[u].push_back({v,w});edge[v].push_back({u,w});}dfs(1,0);for(int tt=1;tt<=q;tt++){int u,x;cin>>u>>x;//加上与原来颜色相同的点之间的连边价值(因为修改后现在的颜色不同)ans+=all[u][color[u]];//子节点if(pa[u])ans+=(color[pa[u]]==color[u])*fs[u];//父节点//减去与现在颜色相同的点之间的连边价值(因为原来颜色不同有代价现在颜色相同无代价)ans-=all[u][x];//子节点if(pa[u])ans-=(color[pa[u]]==x)*fs[u];//父节点if(pa[u]){//对父节点维护的信息进行更新all[pa[u]][color[u]]-=fs[u];if(all[pa[u]][color[u]]==0)all[pa[u]].erase(color[u]);all[pa[u]][x]+=fs[u];}color[u]=x;cout<<ans<<"\n";}
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}

G1

题意

给定数组a[],求价值最大的子串(子串的价值定义为med(a[l]…a[r])-min(a[l~r])),其中med代表a[l~r]的中位数,min代表a[l~r]的最小数。

中位数是值第ceil((len+1)/2)小的元素,len代表长度

特殊限定:a[i]<=100

思路

我们考虑枚举可能的中位数。

由于题目中 a[i] ≤ 100,所以我们可以从 1 到 100 枚举所有可能的中位数 x。

对于每一个 x,我们将原数组 a映射成一个新数组 b,其中:

  • 如果 a[i] < x,则 b[i] = -1
  • 如果 a[i] ≥ x,则 b[i] = 1

这样处理之后,问题转化为:是否存在一个子数组 [l, r],其和 b[l] + b[l+1] + … + b[r] ≥ 0。若存在,则说明中位数 ≥ x 的元素在 [l, r] 内占多数,因而 x可以作为某个子数组的中位数。

那么我们如何找到最小值呢?

首先我们要明确当前的最小值是在合法区间内元素的最小值,即只要一个元素能存在于合法区间中,那么这个元素就可能是最小值。

我们枚举当前这个位置a[i]是否能作为一个合法区间中的元素(即左端点l<=i,右端点r>=i的区间里面是否有一个区间满足区间和>=0),如果可以,则当前a[i]可以作为一个合法区间中的元素,则我们用当前a[i]更新最小值。

那么我们怎么判断是否存在区间和>=0呢,其实很简单,假设当前存在一个区间[l,r],那么区间和就是qzh[r]-qzh[l-1],我们要让qzh[r]尽可能的大,qzh[l-1]尽可能的小,所以只需要维护前缀和最小(qzh[l-1]),后缀和最大(qzh[r])即可,这样能保证区间和最大,在判定a[i]是否能作为合法区间中的元素时,只需要判定suf[i]-pre[i-1]>=0是否成立即可。

代码

#include<bits/stdc++.h>
using namespace std;
void solve(){int n;cin>>n;vector<int>a(n+1);for(int i=1;i<=n;i++)cin>>a[i];int ans=0;for(int mid=1;mid<=100;mid++){vector<int>b(n+1,0);for(int i=1;i<=n;i++)b[i]=(a[i]>=mid?1:-1);for(int i=1;i<=n;i++)b[i]+=b[i-1];vector<int>pre(n+1,0),suf(n+2,0);pre[0]=0;//区间左端点l=1时,qzh[l-1]=qzh[0]=0for(int i=1;i<=n;i++)pre[i]=min(b[i],pre[i-1]);suf[n]=b[n];//区间右端点最大为nfor(int i=n-1;i>=1;i--)suf[i]=max(b[i],suf[i+1]);int mi=0x3f3f3f3f;for(int i=1;i<=n;i++){if(suf[i]-pre[i-1]>=0)mi=min(mi,a[i]);}ans=max(ans,mid-mi);}cout<<ans<<"\n";
}
signed main(){ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);int T__=1;cin>>T__;while(T__--)solve();return 0;
}
http://www.dtcms.com/a/289349.html

相关文章:

  • Centos卷挂载失败系统无法启动
  • 力扣:动态规划java
  • 《剥开洋葱看中间件:Node.js请求处理效率与错误控制的深层逻辑》
  • 深度学习篇---矩阵
  • (保姆级)Windows11安装GPU版本Pytorch2.3、CUDA12.6
  • Python爬虫实战:研究Genius库相关技术
  • 【web安全】SQL注入与认证绕过
  • STM32-第八节-TIM定时器-4(编码器接口)
  • Coze智能体长期记忆功能如何做
  • Muon小记
  • 【vue-6】Vue3 响应式数据声明:深入理解 ref()
  • MVP 设计指南:从需求池到产品落地的最小可行路径
  • ABP VNext + Grafana Loki:集中式日志聚合
  • 服装工厂生产管理软件最新核心排名是什么?
  • [simdjson] document_stream | iterate_many() | batch_size | 线程加速 | 轻量handle
  • Pycharm的Terminal打开后默认是python环境
  • 网工实验——路由器小项目
  • 每日面试题10:令牌桶
  • tidyverse-数据可视化 - 图形的分层语法
  • 论文分享(一)
  • C++ primer知识点总结
  • LVS-----TUN模式配置
  • Docker-compose-知识总结
  • 基于单片机倾角测量仪/角度测量/水平仪
  • 双8无碳小车“cad【17张】三维图+设计说名书
  • 【HarmonyOS】ArkUI - 自定义组件和结构重用
  • 【pandoc实践】如何将wordpress文章批量导出为Markdown格式
  • 神经网络:卷积层
  • 使用UV管理PyTorch项目
  • PyTorch常用的简单数学运算