CSP 模拟 9
T1 大众点评
两两比较,把较大的放一堆,较小的放一堆,然后从这两堆里找出最大最小,理论比较 \(\frac{3n}{2}\) 次。
点击查看代码
#include "ramen.h"
#include "bits/stdc++.h"
void Ramen(int n) {
std::vector<int>a,b;
if(n==1){
Answer(0,0);return;
}
for(int i=0;i<n-1;i+=2){
if(Compare(i,i+1)==1)a.push_back(i),b.push_back(i+1);
else a.push_back(i+1),b.push_back(i);
}
if(n&1)a.push_back(n-1),b.push_back(n-1);
int max=a[0],min=b[0];
for(int i=1;i<a.size();++i){
if(Compare(max,a[i])==-1)max=a[i];
if(Compare(min,b[i])==1)min=b[i];
}
Answer(min,max);
}
T2 录取查询
考虑拿线段树维护区间是否有序,树状数组维护字母的出现次数,看看是否两端字母除外的全在区间里即可。
点击查看代码
#include<bits/stdc++.h>
#define int long long
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=2e5+10,P=131,mod1=998244353,mod2=1e9+7;
char s[N];
int n,q,_p1[N],_p2[N],num[27];
struct HA{int _1,_2,len;};
struct TREE{
int hash1,hash2,l,r;
}t[N<<2];
inline void add(HA&a,HA b){
a._1=(a._1*_p1[b.len]%mod1+b._1)%mod1;
a._2=(a._2*_p2[b.len]%mod2+b._2)%mod2;
a.len+=b.len;
}
inline void update(int p){
int ls=p<<1,rs=p<<1|1;
t[p].hash1=(t[ls].hash1*_p1[t[rs].r-t[rs].l+1]%mod1+t[rs].hash1)%mod1;
t[p].hash2=(t[ls].hash2*_p2[t[rs].r-t[rs].l+1]%mod2+t[rs].hash2)%mod2;
}
inline void build(int p,int l,int r){
t[p].l=l,t[p].r=r;
if(l==r){
num[s[l]-'a']++;
t[p].hash1=t[p].hash2=(int)s[l];return;
}
int mid=l+r>>1;
build(p<<1,l,mid);build(p<<1|1,mid+1,r);
update(p);
}
inline void insert(int p,int l,int r,int pos,int x){
if(l==r){t[p].hash1=t[p].hash2=x;return;}
int mid=l+r>>1;
if(pos<=mid)insert(p<<1,l,mid,pos,x);
else insert(p<<1|1,mid+1,r,pos,x);
update(p);
}
inline HA query(int p,int l,int r,int x,int y){
if(l>=x&&r<=y){return HA{t[p].hash1,t[p].hash2,r-l+1};}
int mid=l+r>>1;HA res={0,0,0};
if(x<=mid)add(res,query(p<<1,l,mid,x,y));
if(y>mid)add(res,query(p<<1|1,mid+1,r,x,y));
return res;
}
int hash1[26][N],hash2[26][N];
inline void ask(int l,int r){
int pos=0,ll=l,rr=r;
char ch=s[l];
while(ll<=rr){
int mid=ll+rr>>1;
if(s[mid]==ch)ll=mid+1,pos=mid;
else rr=mid-1;
}
if(pos-ll+1>num[ch-'a']||s[l]>s[r]){std::cout<<"No\n";return;}
int x=0;
for(int i=0;i<ch-'a';++i)x+=num[i];
int len=pos-l+1;x+=num[ch-'a']-len;
int y=x+r-l+1;
int zc=x;
if(y>n){std::cout<<"No\n";return;}
auto it=query(1,1,n,l,r);
int hash_1=0,hash_2=0;
if(x+len<=y){
hash_1=hash1[ch-'a'][len],hash_2=hash2[ch-'a'][len];
x+=len;
zc=ch-'a';
for(int i=ch-'a'+1;x+num[i]<=y&&i<s[r]-'a';++i){
x+=num[i];
hash_1=(hash_1*_p1[num[i]]%mod1+hash1[i][num[i]])%mod1;
hash_2=(hash_2*_p2[num[i]]%mod2+hash2[i][num[i]])%mod2;
zc=i;
}
}
len=y-x;
zc++;
hash_1=(hash_1*_p1[len]%mod1+hash1[zc][len])%mod1;
hash_2=(hash_2*_p2[len]%mod2+hash2[zc][len])%mod2;
if(hash_1==it._1&&hash_2==it._2){std::cout<<"Yes\n";return;}
else{std::cout<<"No\n";return;}
}
inline void init(){
_p1[0]=_p2[0]=1;
for(int i=1;i<=n;++i)_p1[i]=_p1[i-1]*P%mod1,_p2[i]=_p2[i-1]*P%mod2;
for(int i=0;i<=25;++i){
for(int j=1;j<=n;++j){
hash1[i][j]=(hash1[i][j-1]*P+i+'a')%mod1;
hash2[i][j]=(hash2[i][j-1]*P+i+'a')%mod2;
}
}
build(1,1,n);
}
signed main(){
// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
std::cin>>n;std::cin>>s+1;std::cin>>q;
init();
for(int i=1;i<=q;++i){
int op;std::cin>>op;
if(op==1){
int pos;char ch;std::cin>>pos>>ch;
num[s[pos]-'a']--;num[ch-'a']++;
s[pos]=ch;
insert(1,1,n,pos,(int)ch);
}else{
int l,r;std::cin>>l>>r;
ask(l,r);
}
}
}
T3 精准打击
贪心删尽量大的一定最优,钦定删子树,留剩下的,这样显然会有更优的方案在删去的子树中。所以考虑枚举从多大的子树删,保证一定考虑到答案所在情况。
点击查看代码
#include<bits/stdc++.h>
#define int __int128
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=66;
int d,k,x,num[N],con[N];
signed main(){
// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
int T=read();
num[0]=1;
while(T--){
d=read(),k=read(),x=read();
int ans=2e20;
for(int w=1;w<=d;++w){
int res=1;
if(w==d)res=0;
int _p=1;
bool pd=0;
for(int i=1;i<=w;++i){
num[i]=num[i-1]+_p*k;
_p*=k;
if(num[i-1]==x){pd=1;break;}
}
_p=1;
for(int i=w;i>=0;--i){
con[i]=_p;_p*=k;
}
if(pd){res++;ans=std::min(ans,res);continue;}
if(num[w]==x){ans=std::min(ans,res);continue;}
if(num[w]<=x)continue;
int sum=num[w]-x;
for(int i=w-1;i>=0;--i){
if(!sum)break;
int zc=std::min(sum/num[i],con[i]);
sum-=zc*num[i];res+=zc;
}
ans=std::min(ans,res);
}
std::cout<<(ll)ans<<'\n';
}
}
T4 你画我猜
究极抽象提交答案爆搜题,不会。
总结
这场烂没了,T1 一直在想 GCD Querys,然后降智不会,T2 直接想了用线段树维护哈希值,常数大还难写,细节还多。赛时写锅了,赛后改了,对于一些前后字母相同的没处理到位。T3没时间做,可惜了,T4爆搜其实还是有些分的,期望 300pts。

浙公网安备 33010602011771号