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。

posted @ 2024-08-18 21:36  Ishar-zdl  阅读(34)  评论(0)    收藏  举报