AcWing 第12场周赛题解
数组去重
从后往前扫一遍数组,找到未被标记的数,存下来,标记;已经被标记的就不用存下来
- code
#include<iostream>
#include<cstring>
using namespace std;
int n;
const int maxn=55;
bool book[maxn*20];
int a[maxn];
int st[maxn],top=0;
int main(){
int t;cin>>t;
while(t--){
cin>>n;memset(book,0,sizeof(book));
for(int i=1;i<=n;++i) cin>>a[i];
for(int i=n;i>=1;--i){
if(book[a[i]]==0){
book[a[i]]=1;
st[++top]=a[i];
}
}
cout<<top<<endl;
while(top>=1) cout<<st[top--]<<" ";
cout<<endl;
}
return 0;
}
构造字符串
字典序比较优先级
1.从左至右第一个不同字母的ASCII码大小关系
2.字符串长度
解释完后就可以看一下构造字符数组的要求
- 构成的字符串长度一定为k
- 那这里就分两种情况讨论
1.t比s长
2.t比s短或相等
- t一定比s字典序大
- t字典序尽可能小
- 组成t的字母组成集合\(\in\)s字母构成的集合
2,3条件一合并,即为找字典序大于s的最小字符串
根据后面的条件
当 s比t长 时
先输出t,后面再加上集合中的最小字符
当 s比t短 时
根据字典序的定义,从头开始比较,满足字典序大于s那么就只需要有一个字符比当前位置的s的字符大,在这个位置前面的字符均相等即可
但又要满足最小字典序,所以我们在某个位置之后需要用最小字母来补足长度
此时只需要从后往前找即可(改变的字母的个数越少越好,因为改变的越少,t越接近s)
- code
#include<cstring>
#include<iostream>
using namespace std;
string s;
bool book[33];
int n,k;const int maxn=1e5+10;
int t;
int fd(int x){//找出大于s[x]的最小字母
for(int i=0;i<=25;++i)
if(book[i] && 'a'+i>s[x]) return i;
return s[x]-'a'; //找不到,自己便是最大字母
}
void output(int x,int mini) {//输出
for(int i=1;i<x;++i) cout<<s[i];
char c=fd(x)+'a';cout<<c;
for(int i=x+1;i<=k;++i){
c='a'+mini;
cout<<c;
}cout<<endl;
}
int main(){
cin>>t;
while(t--){
cin>>n>>k;string ans;
memset(book,0,sizeof(book));
cin>>s;
for(int i=n;i>=1;--i) s[i]=s[i-1];
int len=n;
int mini=33;
for(int i=1;i<=len;++i){
book[s[i]-'a']=1;
mini=min(mini,s[i]-'a');
}
if(n<k){
for(int i=1;i<=n;++i) cout<<s[i];
for(int i=n+1;i<=k;++i) {
char c='a'+mini;
cout<<c;
}cout<<endl;
continue;
}
int p=1;
for(int i=k;i>=1;--i){
if(fd(i)>s[i]-'a') {
p=i;
break;
}
}
output(p,mini);
}return 0;
}
环形数组
经典线段树操作
但数组是环形的,这个也好处理
- 当l<=r时 常规线段树操作
- 当r<l时 分为两段操作[l,n-1],[0,r]
区间加减后,值得相对大小不变,最小值还是最小值,直接+即可
输入时注意一下即可
- code
#include<cstdio>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
ll inf=1e18-1;
const ll maxn=2e5+10;
ll ans[maxn<<2];
ll laz[maxn<<2];
int n,m;
int a[maxn];
void push_up(int p){
ans[p]=min(ans[p<<1],ans[p<<1|1]);
}
void build(int p,int l,int r){
if(l==r){
ans[p]=a[l];return ;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
push_up(p);
}
void add(int p,int pf,int l,int r){
ans[p]+=laz[pf];
laz[p]+=laz[pf];return ;
}
void push_down(int p,int l,int r){
int mid=(l+r)>>1;
add(p<<1,p,l,mid);
add(p<<1|1,p,mid+1,r);
laz[p]=0;
}
void update(int p,int l,int r,int nl,int nr,int k){
if(nl<=l && r<=nr){
ans[p]+=k;
laz[p]+=k;
return ;
}
int mid=(l+r)>>1;
push_down(p,l,r);
if(nl<=mid) update(p<<1,l,mid,nl,nr,k);
if(nr>mid) update(p<<1|1,mid+1,r,nl,nr,k);
push_up(p);
}
ll query(int p,int l,int r,int nl,int nr){
if(nl<=l && r<=nr) return ans[p];
ll ret=inf;int mid=(l+r)>>1;
push_down(p,l,r);
if(nl<=mid) ret=min(ret,query(p<<1,l,mid,nl,nr));
if(nr>mid) ret=min(ret,query(p<<1|1,mid+1,r,nl,nr));
return ret;
}
int main(){
scanf("%d",&n);
for(int i=0;i<n;++i) scanf("%d",&a[i]);
scanf("%d",&m);
build(1,0,n-1);
while(m--){
int l,r,k;char c;bool book=0;
scanf("%d %d%c",&l,&r,&c);
if(c=='\n') book=1;
else scanf("%d",&k);
if(l<=r){
if(book) printf("%lld\n",query(1,0,n-1,l,r));
else update(1,0,n-1,l,r,k);
}
else {
if(book) printf("%lld\n",min(query(1,0,n-1,l,n-1),query(1,0,n-1,0,r)));
else {
update(1,0,n-1,l,n-1,k);
update(1,0,n-1,0,r,k);
}
}
}return 0;
}