(https://ac.nowcoder.com/acm/contest/93847)(比赛链接)
目录
A.小苯吃糖果
1.思路
最大的值和剩下的两个值的和比较,取较大的那个输出即可
2.代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int x,y,z;
cin>>x>>y>>z;
int sum = x+y+z;
int max1 = max(x,y);
max1 = max(max1,z);
if(max1>sum-max1){
cout<<max1<<endl;
}else{
cout<<sum-max1<<endl;
}
return 0;
}
B.小苯的排列构造
1.思路
输出长度为n,首项为n,公差为1的递减序列即可
2.代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve(){
int n;
cin>>n;
for(int i=n;i>=1;i--){
cout<<i<<" ";
}
cout<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
}
C.小苯的最小整数
1.思路
通过字符串进行输入,将所有情况都遍历,进行比大小,不断更新最小值。因为数值比较大,将字符串转化为长整型的时候选择用stoll函数进行转化,这里的LLONG_MAX是长整型最大值
2.代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve(){
string s;
cin>>s;
int min1 = LLONG_MAX;
for(int i=0;i<s.length();i++){
string re = s.substr(i+1,s.length());
re += s.substr(0,i+1);
int tt = stoll(re);
min1 = min(min1,tt);
}
cout<<min1<<endl;
}
// 4562827
// 2827456
// 2745628
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
}
D.小苯的蓄水池(easy)
1.思路
数组a保存原始数据,数组b保存更新的结果。利用vis数组来判断某个位置是否更新过,因此对于每次更新操作,通过利用vis数组,来找到受到影响的区间,并通过累加这个区间和,除以平均数,然后对受到影响的这个区间都进行更新,将更新的结果保存在b数组中。对于每次查询,输出b[i]即可
2.代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e3+7;
double a[N],b[N];
int vis[N];
void solve(int n){
int op;
cin>>op;
if(op==1){
int l,r;
cin>>l>>r;
double sum = 0;
int count = 0;
int left=l,right=r;
for(int i=l;i>=1;i--){
if(vis[i]==1){
left = i;
}else{
break;
}
}
for(int i=r;r<=n;i++){
if(vis[i]==1){
right = i;
}else{
break;
}
}
for(int i=left;i<=right;i++){
sum+=a[i];
count++;
}
sum/=count;
for(int i=left;i<=right;i++){
b[i] = sum;
vis[i] = 1;
}
}else if(op==2){
int i;
cin>>i;
printf("%.10lf\n",b[i]);
}
}
signed main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
double t;
cin>>t;
a[i] = t;
b[i] = t;
}
while(m--){
solve(n);
}
}
E.小苯的蓄水池(hard)
1.思路
利用并查集对合并的区域进行维护,每次拆除挡板时,都向右进行合并,并将所有合并的区域的数值都存在最右边的那个父亲节点上,包括区间的长度。查询时,直接寻找其父亲节点,进行输出即可
2.代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+7;
double a[N],fa[N],sz[N]; // a[i]表示合并的区段和,fa[i]表示i的父亲节点,sz[i]表示合并的区段长度
int find(int x){ // 查找父亲节点
if(fa[x]!=x){ // 如果自身不是自己的父亲则递归查找父亲节点,同时更改自己的父亲为对应的节点
return fa[x] = find(fa[x]);
}else{
return x; // 自身是自己的父亲,直接返回即可
}
}
void merge(int l, int r){
int u = find(l); // 查找所要合并的两个水池的父亲节点
int v = find(r);
if(u==v){ // 相同直接退出
return ;
}
if(v<u){ // 保证向大的值,即右侧进行合并
swap(v,u);
}
a[v]+=a[u]; // 区段和累计
sz[v]+=sz[u]; // 区段长度累计
fa[u] = v; // 合并,更新父亲节点
}
void solve(){
int op;
cin>>op;
if(op==1){
int l,r;
cin>>l>>r;
while(l<r){
merge(l,l+1); // 区间合并
l = find(l); // l能直接跳转到其父亲的位置,因为之间的位置一定是合并过的
}
}else if(op==2){
int i;
cin>>i;
int fa = find(i);
printf("%.10lf",a[fa]/sz[fa]);
}
}
signed main(){
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
fa[i] = i; // 默认每个水池位置自己都是自己的父亲
sz[i] = 1; // 默认每个区段长度都为1
}
while(m--){
solve();
}
}
3.官方题目讲解(本周官方题解讲解的很好很详细,强烈建议去看看!)https://www.bilibili.com/video/BV1o3S2YREhu?spm_id_from=333.788.videopod.episodes&vd_source=b0cde2c7518af1c65116188091dadb6d&p=3https://www.bilibili.com/video/BV1o3S2YREhu?spm_id_from=333.788.videopod.episodes&vd_source=b0cde2c7518af1c65116188091dadb6d&p=3
F.小苯的字符提前
1.思路
首先确定第k小的Move串的首字符为什么(如b),遍历字符串,统计每个字符的数量,从小到大进行累计,若小于k说明不在当前字符继续累计求和,否则说明第k小的move串就在以当前字符为首的字符集中。nxt数组用于存储当前字符之后的第一个与当前字符不同的字符的位置。最后从字符串从后往前进行处理,个人认为,因为从后往前处理能够保证每次能直接在双端队列中添加元素。因为这样保证后面的字符已经被处理完,文字难以叙述,强烈建议观看官方题解讲解。
2.代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
int cnt[27]; // 统计字符串中每个字符的个数
void solve(){
for(int i=0;i<26;i++){
cnt[i]=0;
}
int n,k,sum=0,index=-1;
cin>>n>>k;
string s;
cin>>s;
for(auto c:s){
cnt[c-'a']++;
}
for(int i=0;i<26;i++){
if(sum+cnt[i]<k){ // 说明不在当前字符位置
sum+=cnt[i];
}else{
index = i; // 最终结果的move串的首字符即为当前字符
break;
}
}
vector<int>nxt(n); // 存储当前字符之后的第一个与当前字符不同的字符的位置
for(int i=n-1;i>=0;i--){
if(i<n-1&&s[i]==s[i+1]){
nxt[i] = nxt[i+1];
}else{
nxt[i] = i+1;
}
}
deque<int>q; // 存储从小到大排序的结果字符的位置
for(int i=n-1;i>=0;i--){
if((s[i]-'a')!=index){
continue;
}
int x = nxt[i];
if(x<n&&s[i]<s[x]){ // 当前字符小于s[nxt[i]],说明比之后的任意一个move串都大
q.emplace_back(i);
}else{
q.emplace_front(i); // 当前字符大于s[nxt[i]],说明比之后的任意一个move串都小
}
}
for(int i=1;i<k-sum;i++){
q.pop_front(); // 找到第k小的move串的对应的首字符的位置
}
cout<<s[q.front()]<<s.substr(0,q.front())<<s.substr(q.front()+1)<<endl;
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
}
G.小苯的数位MEX
好难不会