2025多校冲刺省选模拟赛12

2025多校冲刺省选模拟赛12

T1 A. 删除数组 0pts

T1 HZTG3024. 发烧(fever) 50pts

  • 原题: CF204E Little Elephant and Strings

  • 部分分

    • 50pts :模拟。
    点击查看代码
    const ll mod=1000003579,base=13331;
    ll jc[100010],a[100010],ans[100010];
    unordered_map<ll,ll>cnt,vis;
    unordered_map<ll,ll>::iterator it;
    vector<ll>hsh[100010],tmp;
    char s[100010];
    void sx_hash(char s[],ll len)
    {
        for(ll i=0;i<=len;i++)  a[i]=(i==0)?0:(a[i-1]*base%mod+s[i])%mod;
    }
    ll ask_hash(ll l,ll r)
    {
        return (a[r]-a[l-1]*jc[r-l+1]%mod+mod)%mod;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("fever.in","r",stdin);
        freopen("fever.out","w",stdout);
    #endif
        ll n,m,len,i,j,l,r;
        cin>>n>>m;
        for(i=0;i<=100000;i++)  jc[i]=(i==0)?1:jc[i-1]*base%mod;
        for(i=1;i<=n;i++)
        {
            cin>>(s+1);  len=strlen(s+1);  tmp.clear();
            sx_hash(s,len);
            for(l=1;l<=len;l++)
            {
                for(r=l;r<=len;r++)  
                {
                    hsh[i].push_back(ask_hash(l,r));
                    tmp.push_back(ask_hash(l,r));
                }
            }
            sort(tmp.begin(),tmp.end());  tmp.erase(unique(tmp.begin(),tmp.end()),tmp.end());
            for(j=0;j<tmp.size();j++)  cnt[tmp[j]]++;
        }
        for(it=cnt.begin();it!=cnt.end();it++)
        {
            if(it->second>=m)  vis[it->first]=1;
        }
        for(i=1;i<=n;i++)
        {
            for(j=0;j<hsh[i].size();j++)  ans[i]+=(vis.find(hsh[i][j])!=vis.end());
        }
        for(i=1;i<=n;i++)  cout<<ans[i]<<" ";
        return 0;
    }
    
  • 正解

    • 将子串转化为后缀的一段前缀,考虑后缀数组。
    • 考虑双指针维护恰好包含 k 个来源不同字符串的后缀的区间, ST 表或单调队列维护 height 的最小值。
      • 双指针需要从左右两边各扫一遍维护极短区间。
    • 在回退时进行统计答案。特判 m=1 的情况。
    点击查看代码
    ll s[200010],ans[200010],col[200010],cnt[200010];
    char t[100010];
    deque<ll>q;
    struct SA
    {
        ll sa[200010],rk[400010],oldrk[400010],id[200010],cnt[200010],key[200010],height[200010];
        ll val(ll x)
        {
            return x;
        }
        void counting_sort(ll n,ll m)
        {
            memset(cnt,0,sizeof(cnt));
            for(ll i=1;i<=n;i++)  cnt[key[i]]++;
            for(ll i=1;i<=m;i++)  cnt[i]+=cnt[i-1];
            for(ll i=n;i>=1;i--)
            {
                sa[cnt[key[i]]]=id[i];
                cnt[key[i]]--;
            }
        }
        void init(ll s[],ll len)
        {
            ll m=200000,tot=0,num=0;
            for(ll i=1;i<=len;i++)
            {
                rk[i]=val(s[i]);  id[i]=i;
                key[i]=rk[id[i]];
            }
            counting_sort(len,m);
            for(ll w=1;tot!=len;w<<=1,m=tot)
            {
                num=0;
                for(ll i=len;i>=len-w+1;i--)
                {
                    num++;  id[num]=i;
                }
                for(ll i=1;i<=len;i++)
                {
                    if(sa[i]>w)
                    {
                        num++;  id[num]=sa[i]-w;
                    }
                }
                for(ll i=1;i<=len;i++)  key[i]=rk[id[i]];
                counting_sort(len,m);
                for(ll i=1;i<=len;i++)  oldrk[i]=rk[i];
                tot=0;
                for(ll i=1;i<=len;i++)
                {
                    tot+=(oldrk[sa[i]]!=oldrk[sa[i-1]]||oldrk[sa[i]+w]!=oldrk[sa[i-1]+w]);
                    rk[sa[i]]=tot;
                }
            }
            for(ll i=1,j=0;i<=len;i++)
            {
                for(j-=(j>=1);s[i+j]==s[sa[rk[i]-1]+j];j++);
                height[rk[i]]=j;
            }
        }
    }S;
    void add(ll x,ll &sum)
    {
        if(col[x]!=0)
        {
            cnt[col[x]]++;
            sum+=(cnt[col[x]]==1);
        }
    }
    void del(ll x,ll &sum)
    {
        if(col[x]!=0)
        {
            cnt[col[x]]--;
            sum-=(cnt[col[x]]==0);
        }
    }
    struct SMT
    {
        struct SegmentTree
        {
            ll lazy;
        }tree[800010];
        #define lson(rt) (rt<<1)
        #define rson(rt) (rt<<1|1)
        void update(ll rt,ll l,ll r,ll x,ll y,ll val)
        {
            if(x<=l&&r<=y)
            {
                tree[rt].lazy=max(tree[rt].lazy,val);
                return;
            }
            ll mid=(l+r)/2;
            if(x<=mid)  update(lson(rt),l,mid,x,y,val);
            if(y>mid)  update(rson(rt),mid+1,r,x,y,val);
        }
        ll query(ll rt,ll l,ll r,ll pos)
        {
            if(l==r)  return tree[rt].lazy;
            ll mid=(l+r)/2;
            return max(tree[rt].lazy,(pos<=mid)?query(lson(rt),l,mid,pos):query(rson(rt),mid+1,r,pos));
        }
    }T;
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("fever.in","r",stdin);
        freopen("fever.out","w",stdout);
    #endif
        ll n,m,len=0,_len,sum=0,i,j;
        cin>>n>>m;
        for(i=1;i<=n;i++)
        {
            scanf("%s",t+1);  _len=strlen(t+1);
            for(j=1;j<=_len;j++)
            {
                len++;  s[len]=t[j]-'a'+1;
                col[len]=i;
            }
            len++;  s[len]=100000+i;
            ans[i]=(m==1)*_len*(_len+1)/2;
        }
        S.init(s,len);
        for(i=1,j=1;i<=len&&m!=1;i++)
        {
            add(S.sa[i],sum);
            while(q.empty()==0&&S.height[q.back()]>=S.height[i])  q.pop_back();
            q.push_back(i);
            for(;sum>=m;j++)
            {
                if(q.empty()==0&&S.sa[j]==S.sa[q.front()])  q.pop_front();// j+1 ~ i 的最小值
                T.update(1,1,len,j,i,S.height[q.front()]);
                if(sum==m&&cnt[col[S.sa[j]]]==1)  break;// 删去后有些情况会统计不到
                del(S.sa[j],sum);
            }
        }
        for(i=1;i<=len&&m!=1;i++)  ans[col[S.sa[i]]]+=T.query(1,1,len,i);
        for(i=1;i<=n;i++)  cout<<ans[i]<<" ";
        return 0;
    }
    

T2 B. 千岛题 60pts

  • 部分分

    • 20pts
      • 由排序不等式,先按照 b 降序排序,然后做背包 DP
      • fi,j 表示前 i 个数中选择了 j 个的最小代价,状态转移方程为 fi,j=min(fi1,j,fi1,j1+bi(j1)+ai)
    • 60pts :观察到每次修改的都是一段后缀,且分界点前后具有单调性,可以借此来进行剪枝。
    点击查看代码
    ll f[300010];
    pair<ll,ll>c[300010];
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("check.in","r",stdin);
        freopen("check.out","w",stdout);
    #endif
        ll n,m,ans=0,i,j;
        cin>>n>>m;
        for(i=1;i<=n;i++)  cin>>c[i].second;
        for(i=1;i<=n;i++)  cin>>c[i].first;
        sort(c+1,c+1+n,greater<pair<ll,ll> >());
        memset(f,0x3f,sizeof(f));  f[0]=0;
        for(i=1;i<=n;i++)
        {
            for(j=i;j>=1&&f[j]>f[j-1]+c[i].first*(j-1)+c[i].second;j--)
                f[j]=f[j-1]+c[i].first*(j-1)+c[i].second;
        }
        for(i=n;i>=0;i--)
        {
            if(f[i]<=m)  
            {
                ans=i;
                break;
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    
    
    • 口胡
      • 转移中一段后缀均从 fi1,j1 转移过来时可以看做分界点 i 整体向右覆盖一位,然后权值加上 bi(j1)+ai 。不妨将 fi,jfi,j1 存储在 i 节点上,维护 bi,j,ai 三个懒惰标记,可持久化平衡树支持区间复制,需要定期重构,大概 20 多次。

      • 二分找到分界点,时间复杂度为 O(nlog2n) ,可能会被卡常。

      • 进一步优化的做法可能类似 CF573E Bear and Bowling

        代码还没写完,不写了
        ll f[100010];
        pair<ll,ll>c[100010];
        struct BST
        {
            ll root,rt_sum;
            struct FHQ_Treap
            {	
                ll son[2],siz,val,id,add,mul,lazy;
            }tree[6501110];
            #define lson(rt) (tree[rt].son[0])
            #define rson(rt) (tree[rt].son[1])
            ll build_rt()
            {
                rt_sum++;
                lson(rt_sum)=rson(rt_sum)=tree[rt_sum].val=tree[rt_sum].id=tree[rt_sum].add=tree[rt_sum].lazy=0;
                tree[rt_sum].siz=tree[rt_sum].mul=1;
                return rt_sum;
            }
            ll copy_rt(ll rt)
            {
                rt_sum++;
                tree[rt_sum]=tree[rt];
                return rt_sum;
            }
            void pushup(ll rt)
            {
                tree[rt].siz=tree[lson(rt)].siz+tree[rson(rt)].siz+1;
            }
            void pushlazy(ll &rt,ll add,ll mul,ll lazy)
            {
                if(add==0&&mul==0&&lazy==0)  return;
                rt=copy_rt(rt);
                tree[rt].id+=lazy;
                tree[rt].lazy+=lazy;
                tree[rt].val+=mul*tree[rt].id+add;
                tree[rt].add+=add;
                tree[rt].mul+=mul;
            }
            void pushdown(ll rt)
            {
                pushlazy(lson(rt),tree[rt].add,tree[rt].mul,tree[rt].lazy);
                pushlazy(rson(rt),tree[rt].add,tree[rt].mul,tree[rt].lazy);
                tree[rt].add=tree[rt].lazy=0;  tree[rt].mul=1;
            }
            void split(ll rt,ll k,ll &x,ll &y)
            {
                cerr<<rt<<" "<<k<<" "<<x<<" "<<y<<endl;
                if(rt==0||k==0)
                {
                    x=y=0;
                    return;
                }
                pushdown(rt);
                if(tree[lson(rt)].siz+1<=k)
                {
                    x=copy_rt(rt);
                    split(rson(rt),k-tree[lson(rt)].siz-1,rson(x),y);
                    pushup(x);
                }
                else
                {
                    y=copy_rt(rt);
                    split(lson(rt),k,x,lson(y));
                    pushup(y);
                }
            }
            ll merge(ll rt1,ll rt2)
            {
                if(rt1==0||rt2==0)  return rt1+rt2;
                ll rt;
                pushdown(rt1);  pushdown(rt2);
                if(rand()%(tree[rt1].siz+tree[rt2].siz)<tree[rt1].siz)
                {
                    rt=copy_rt(rt1);
                    rson(rt)=merge(rson(rt),rt2);
                }
                else
                {
                    rt=copy_rt(rt2);
                    lson(rt)=merge(rt1,lson(rt));
                }
                pushup(rt);
                return rt;
            }
            void update(ll id,ll b,ll a)
            {
                ll l=2,r=id,ans=id,mid,x,y,z,_z;
                while(l<=r)
                {
                    mid=(l+r)/2;
                    split(root,mid,x,y);
                    split(x,mid-2,x,z);
                    split(z,1,_z,z);
                    if(tree[z].val>tree[_z].val+(tree[_z].id-1)*b+a)
                    {
                        ans=mid;
                        r=mid-1;
                    }
                    else
                    {
                        l=mid+1;
                    }
                    root=merge(merge(merge(x,_z),z),y);
                }
                split(root,ans-1,x,y);
                y=copy_rt(y);  pushlazy(y,a,b,1);
                root=merge(x,copy_rt(y));
            }
            ll query(ll id)
            {
                ll x,y,z,ans;
                split(root,id+1,x,y);
                split(root,id,x,z);
                ans=tree[z].val;
                root=merge(merge(x,z),y);
                return ans;
            }
        }T;
        int main()
        {
        // #define Isaac
        #ifdef Isaac
            // freopen("check.in","r",stdin);
            // freopen("check.out","w",stdout);
            freopen("in.in","r",stdin);
            freopen("out.out","w",stdout);
        #endif
            ll n,m,ans=0,i;
            cin>>n>>m;
            for(i=1;i<=n;i++)  cin>>c[i].second;
            for(i=1;i<=n;i++)  cin>>c[i].first;
            sort(c+1,c+1+n,greater<pair<ll,ll> >());
            T.root=T.build_rt();
            for(i=1;i<=n;i++)
            {
                T.update(i,c[i].first,c[i].second);
            }
            for(i=n;i>=0;i--)
            {
                if(T.query(i)<=m)  
                {
                    ans=i;
                    break;
                }
            }
            cout<<ans<<endl;
            return 0;
        }
        
  • 正解

T3 C. 车 15pts

  • 部分分

    • 15pts :爆搜。
    点击查看代码
    ll a[200010],b[200010],c[200010],cnt[200010],ans=0x3f3f3f3f3f3f3f3f;
    void dfs(ll pos,ll n,ll m)
    {
        if(pos==m+1)
        {
            ll maxx=0;
            for(ll i=1;i<=n;i++)  maxx=max(maxx,cnt[i]);
            ans=min(ans,maxx);
        }
        else
        {
            for(ll i=1;i<=n;i++)  cnt[i]+=(a[pos]<=i&&i<=b[pos]-1);
            dfs(pos+1,n,m);
            for(ll i=1;i<=n;i++)  cnt[i]-=(a[pos]<=i&&i<=b[pos]-1);
            for(ll i=1;i<=n;i++)  cnt[i]+=(i<=a[pos]-1||i>=b[pos]);
            dfs(pos+1,n,m);
            for(ll i=1;i<=n;i++)  cnt[i]-=(i<=a[pos]-1||i>=b[pos]);
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("tickets.in","r",stdin);
        freopen("tickets.out","w",stdout);
    #endif
        ll n,m,i;
        cin>>n>>m;
        for(i=1;i<=m;i++)
        {	
            cin>>a[i]>>b[i]>>c[i];
            if(a[i]>b[i])  swap(a[i],b[i]);
        }
        dfs(1,n,m);
        cout<<ans<<endl;
        return 0;
    }
    
  • 正解

总结

  • 无意义罚坐。

后记

  • T1 暑假模拟赛时出过,遂 feifei 把题换了。
posted @   hzoi_Shadow  阅读(41)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
历史上的今天:
2024-02-14 2024寒假自主提升日记
扩大
缩小
点击右上角即可分享
微信分享提示