首页 > 其他分享 >[71] (多校联训) A层冲刺NOIP2024模拟赛24

[71] (多校联训) A层冲刺NOIP2024模拟赛24

时间:2024-11-19 18:20:17浏览次数:1  
标签:24 int mid 1000002 多校 1000001 联训 端点 ffffff

byd T3 放道这种题有什么深意吗

flowchart TB A(选取字符串) style A color:#ffffff,fill:#00c0c0,stroke:#ffffff

确实是签,但是一直在想组合意义,最后因为没提前处理逆元遗憾离场了,赛后看题解发现的确是往树上转化更简单点

赛时的组合意义代码

没过

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=998244353,num=233;
int k;
string s;
int pi[1000002];
int fact[1000002];
int tp[1000002],ct[1000002];
vector<int>v;
int power(int a,int t){
    int base=a,ans=1;
    while(t){
        if(t&1){
            ans=ans*base%p;
        }
        base=base*base%p;
        t>>=1;
    }
    return ans;
}
int C(int n,int m){
    return fact[n]*power(fact[n-m]*fact[m]%p,p-2)%p;
}
signed main(){
    // freopen("sam/T1/ex.in","r",stdin);
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    cin>>k>>s;
    s=" "+s;
    basenum[0]=1;
    fact[0]=1;
    for(int i=1;i<=(int)s.length();++i){
        if(i!=(int)s.length()) h[i]=h[i-1]*num+s[i];
        if(i!=(int)s.length()) basenum[i]=basenum[i-1]*num;
        fact[i]=fact[i-1]*i%p;
    }
    for(int i=2;i<=(int)s.length()-1;++i){
        int j=pi[i-1];
        while(j>0 and s[j+1]!=s[i]) j=pi[j];
        if(s[j+1]==s[i]) j++;
        pi[i]=j;
    }
    for(int i=1;i<=(int)s.length()-1;++i){
        int j=i;
        while(j>0){
            tp[j]++;
            ct[i]++;
            j=pi[j];
        }
    }
    int ans=C((int)s.length(),k);
    for(int i=1;i<=(int)s.length()-1;++i){
        ans=(ans+C(tp[i],k)*((ct[i]+1)*(ct[i]+1)-ct[i]*ct[i])%p)%p;
    }
    cout<<ans<<endl;
}

组合意义的大体思路是先处理出所有 border,然后枚举每个前缀,然后再枚举以这个前缀为公共前后缀(不一定非得是 border)的前缀数量(这句话有点绕,形式化地说,设 \(t=b(s)\) 表示 \(t\) 既是 \(s\) 的前缀也是 \(s\) 的后缀,我们要统计的就是,对于给定的 \(i\),满足 \(s_{[1,i]}=b(s_{[1,j]})\) 的 \(j\) 的数量 \(a\),不难发现这个 \(i\) 对答案的贡献就是 \(C^{k}_{a}\) 乘一个什么系数),我们组合意义要求的就是这个系数,通过手摸可以发现,如果满足 \(s_{[1,k]}=b(s_{[1,i]})\) 的 \(k\) 有 \(c\) 个,那么这个系数是 \(c^2-(c-1)^2=2c-1\),所以直接做就行了

然后是题解给的树上意义的解法

如果将 \(i\) 与 \(p_i\) 连边(\(p_i\) 是 \(s_{[1,i]}\) 的 border 长度),发现可以连成一颗树,选 \(k\) 个字符串找公共前后缀的实质是在树上选 \(k\) 个点求 LCA,对答案的贡献是 LCA 的深度的平方

这个转化还挺有意思的

然后需要做的就只有枚举每个点作为公共 LCA 的情况,容易发现只有在子树里选才行,方案为 \(C_{size}^{k}\),注意要减去所有点都出现在同一颗子树里的情况

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int p=998244353;
int k,ans;
int pi[1000002];
string s;
int fact[1000002],inv[1000002],invfact[1000002];
vector<int>e[1000001];
inline int C(int n,int m){
    if(n<m) return 0;
    return fact[n]*invfact[m]%p*invfact[n-m]%p;
}
int sizen[1000001];
void dfs(int now,int deep){
    sizen[now]=1;
    int tot=0;
    for(int i:e[now]){
        dfs(i,deep+1);
        sizen[now]+=sizen[i];
        tot=(tot+C(sizen[i],k))%p;
    }
    ans=(ans+(C(sizen[now],k)%p-tot+p)%p*(deep*deep)%p)%p;
}
signed main(){
    freopen("string.in","r",stdin);
    freopen("string.out","w",stdout);
    cin>>k>>s;
    s=" "+s;
    for(int i=2;i<=(int)s.length()-1;++i){
        int j=pi[i-1];
        while(j and s[j+1]!=s[i]) j=pi[j];
        if(s[j+1]==s[i]) j++;
        pi[i]=j;
    }
    for(int i=1;i<=(int)s.length()-1;++i){
        e[pi[i]].push_back(i);
    }
    inv[1]=1;
    for(int i=2;i<=1000001;++i){
        inv[i]=inv[p%i]*(p-p/i)%p;
    }
    fact[0]=invfact[0]=1;
    for(int i=1;i<=1000001;++i){
        fact[i]=fact[i-1]*i%p,invfact[i]=invfact[i-1]*inv[i]%p;
    }
    dfs(0,1);
    cout<<ans;
}
flowchart TB A(取石子) style A color:#ffffff,fill:#00c0c0,stroke:#ffffff

tba

flowchart TB A(均衡区间) style A color:#ffffff,fill:#00c0c0,stroke:#ffffff

考虑直接钦定一个定点(题目里也是让这么求的),然后枚举区间另一个端点的所有可能情况

发现这个东西完全没有单调性,这很不好,于是考虑做 trick

怎么才能套上 trick,考虑到如果你只钦定左端点 \(l\) 满足条件(即找符合条件的 \(r\ge l\),满足 \(a_l\neq\max\limits_{l\le i\le r}a_i,a_l\neq\min\limits_{l\le i\le r}a_i\),其实就是把题目里对于右端点的限制撤了),你会发现这个玩意是有单调性的,对于所有的 \(r\) 大于某个定值都成立,因此可以二分去找这个值

对右端点,你用同样的情况去找满足条件的 \(l\),然后尝试枚举所有的左右端点,尝试从中间合并它俩,如果能合并就合法(合并的条件是,左端点的合法区间包含右端点,右端点的合法区间包含左端点,这样在区间里左右端点就一定都符合条件了)

设对左端点 \(l\),其合法区间是 \([a_l,n]\),对右端点 \(r\),其合法区间是 \([1,b_r]\),其实现在我们要找的就是满足 \(r\ge a_l,l\le b_r\) 的 \((l,r)\) 的数量

这东西复杂度太高,考虑直接上个啥数据结构维护一下

上权值树状数组(线段树亦可,但是比较危险),按 \(a_i\) 从大到小枚举所有 \(a_i\),然后将 \(j\in[a_l,n]\) 的 \(j\) 动态地插入树状数组内,现在只需要查这些插进去的数里有几个是包含 \(i\) 的,贪心地想,插入的时候可以把每个区间插到其右端点上,查询的时候,只要右端点在 \(i\) 右侧的均包含 \(i\)(因为原区间是 \([1,r]\)),因此直接查 \([i,n]\) 内点的数量即可

另一边也是同理做

#include<bits/stdc++.h>
using namespace std;
int n,id;
int a[1000001],lg2[1000001];
int stmaxn[20][1000001],stminn[20][1000001];
inline int qmax(int l,int r){
    int tmp=lg2[r-l+1];
    return max(stmaxn[tmp][l],stmaxn[tmp][r-(1<<tmp)+1]);
}
inline int qmin(int l,int r){
    int tmp=lg2[r-l+1];
    return min(stminn[tmp][l],stminn[tmp][r-(1<<tmp)+1]);
}
struct stree{
    struct tree{
        int sum;
    }t[1000001*4];
    #define tol (id*2)
    #define tor (id*2+1)
    #define mid(l,r) mid=((l)+(r))/2
    void change(int id,int l,int r,int pos){
        if(l==r){
            t[id].sum++;
            return;
        }
        int mid(l,r);
        if(pos<=mid) change(tol,l,mid,pos);
        else change(tor,mid+1,r,pos);
        t[id].sum=t[tol].sum+t[tor].sum;
    }
    int ask(int id,int l,int r,int L,int R){
        if(L<=l and r<=R){
            return t[id].sum;
        } 
        int mid(l,r);
        if(R<=mid) return ask(tol,l,mid,L,R);
        else if(L>=mid+1) return ask(tor,mid+1,r,L,R);
        return ask(tol,l,mid,L,mid)+ask(tor,mid+1,r,mid+1,R);
    }
}A,B;
int la[1000001],rb[1000001];
struct la_t{
    int la,id;
    inline bool operator<(const la_t&A)const{
        return la>A.la;
    }
}lat[1000001];
struct rb_t{
    int rb,id;
    inline bool operator<(const rb_t&A)const{
        return rb<A.rb;
    }
}rbt[1000001];
int ansla[1000001],ansrb[1000001];
int main(){
    ios::sync_with_stdio(false);
    cin>>n>>id;
    for(int i=1;i<=n;++i){
        cin>>a[i];
        if(i!=1) lg2[i]=lg2[i/2]+1;
        stmaxn[0][i]=stminn[0][i]=a[i];
    }
    for(int i=1;i<=19;++i){
        for(int j=1;j<=n;++j){
            stmaxn[i][j]=max(stmaxn[i-1][j],stmaxn[i-1][j+(1<<(i-1))]);
            stminn[i][j]=min(stminn[i-1][j],stminn[i-1][j+(1<<(i-1))]);
        }
    }
    for(int i=1;i<=n;++i){
        int l=i+1,r=n,ans=n+1;
        while(l<=r){
            int mid=(l+r)/2;
            if(qmax(i,mid)!=a[i] and qmin(i,mid)!=a[i]){
                r=mid-1;
                ans=mid;
            }
            else l=mid+1;
        }
        lat[i].la=ans;
        lat[i].id=i;
        la[i]=ans;
        // cout<<i<<" ["<<ans<<" "<<n<<"]"<<endl;
    }
    // cout<<endl;
    for(int i=1;i<=n;++i){
        int l=1,r=i-1,ans=0;
        while(l<=r){
            int mid=(l+r)/2;
            if(qmax(mid,i)!=a[i] and qmin(mid,i)!=a[i]){
                l=mid+1;
                ans=mid;
            }
            else r=mid-1;
        }
        rbt[i].rb=ans;
        rbt[i].id=i;
        rb[i]=ans;
        // cout<<i<<" ["<<1<<" "<<ans<<"]"<<endl;
    }
    sort(lat+1,lat+n+1);
    sort(rbt+1,rbt+n+1);
    int j=n+1;
    for(int i=1;i<=n;++i){
        if(lat[i].la==n+1) continue;
        while(j!=lat[i].la){
            j--;
            if(rb[j]!=0) B.change(1,1,n,rb[j]);
        }
        ansla[lat[i].id]=B.ask(1,1,n,lat[i].id,n);
    }
    j=0;
    for(int i=1;i<=n;++i){
        if(rbt[i].rb==0) continue;
        while(j!=rbt[i].rb){
            j++;
            if(la[j]!=n+1) A.change(1,1,n,la[j]);
        }
        ansrb[rbt[i].id]=A.ask(1,1,n,1,rbt[i].id);
    }
    for(int i=1;i<=n;++i){
        cout<<ansla[i]<<' ';
    }
    cout<<endl;
    for(int i=1;i<=n;++i){
        cout<<ansrb[i]<<' ';
    }
    cout<<endl;
}

标签:24,int,mid,1000002,多校,1000001,联训,端点,ffffff
From: https://www.cnblogs.com/HaneDaCafe/p/18555230

相关文章

  • 20222315 2024-2025-1 《网络与系统攻防技术》实验五实验报告
    1、实验内容1)从www.besti.edu.cn、baidu.com、sina.com.cn中选择一个DNS域名进行查询,获取如下信息:DNS注册人及联系方式该域名对应IP地址IP地址注册人及联系方式IP地址所在国家、城市和具体地理位置PS:使用whois、dig、nslookup、traceroute、以及各类在线和离线工具进行搜集......
  • 20222322 2024-2025-1 《网络与系统攻防技术》实验六实验报告
    1.实验内容掌握使用Metasploit和nmap等工具进行前期渗透的方法,并利用四种特定的漏洞对靶机进行攻击。(1)掌握Metasploit和nmap的用法学习并熟悉Metasploit框架的基本操作,包括模块搜索(Search)、使用(Use)、展示选项(Show)、设置参数(Set)以及执行攻击(Exploit/run)的流程。(2)学习前期渗透的......
  • 20222303 2024-2025-1 《网络与系统攻防技术》实验五实验报告
    1.实验内容对网站进行DNS域名查询,包括注册人、IP地址等信息,还通过相关命令查询IP地址注册人及地理位置。尝试获取QQ好友IP地址并查询其地理位置。使用nmap对靶机环境扫描,获取靶机IP活跃状态、开放端口、操作系统版本、安装服务等信息。使用Nessus对靶机环境扫......
  • 2024下半年软考各地报名人数汇总!这些地区软考最火爆!
    2024年下半年软考已经结束,部分地区也公布了2024下半年软考报考人数,让我们一起看看今年软考的热度如何吧!从目前的数据来看,软考的热度依旧不减。尤其是广东地区,预计报名人数高达18.4万人;湖南、云南和陕西省都是1万多人;浙江10个市加起来的报名人数共36440人,其中杭州报名人数共284......
  • MS5146T/MS5147T/MS5148T——2kSPS、24bit Σ-Δ ADC
    产品简述MS5146T/MS5147T/MS5148T是适合高精度、低成本测量应用的24bit模数转换器。其内部集成低噪声可编程增益放大器、高精度Δ-Σ模数转换器和内部振荡器。MS5147T和MS5148T内部还集成低温漂基准和两路匹配的可编程电流源。M......
  • 【刷题笔记】[BalticOI 2024] Portal
    【刷题笔记】[BalticOI2024]Portal\(Solution\)先注意到,题目中的图形是许多的自相似图形,要求能满足要求的单位图形的最大面积先考虑只有一维的情况,设几个传送门的坐标为\((a_i,0)\)```发现将整个图形平移后答案不会改变,所以不妨把一个传送门移动到\((0,0)\)可以发现单......
  • 24.11.19
    今日写大作业实验三:JFinal极速开发框架实验 (2024.11.29日前完成)    根据参考资料,学习JFinal极速开发框架的使用并如下任务:    任务一:了解Maven及其使用方法,总结其功能作用(占20%)    任务二:学习JFinal框架,基于Maven建立JFinal工程,并对JFinal框架功能进行总结介绍(占3......
  • 微软Office 2021 24年11月授权版
    概述MicrosoftOfficeLTSC2021专业增强版是微软公司推出的一款专为企业客户设计的办公软件套件。该版本于2024年11月进行了批量许可版更新推送,旨在为企业用户提供更加稳定、高效的办公体验。主要特点LOGO设计趋势强化:新版Office将棱角改为圆角风格,提高了企业的辨识度。......
  • 帝国CMS存在SQL注入漏洞(CNVD-2024-4321448、CVE-2023-50073)
    帝国CMS(EmpireCMS )是一款非常出名的网站管理系统,用户也非常多。 国家信息安全漏洞共享平台于2024-11-06公布其存在SQL注入漏洞。漏洞编号:CVE-2024-44725、CNVD-2024-43215影响产品:帝国CMSV7.5漏洞级别:高公布时间:2024-11-06漏洞描述:帝国CMS v7.5版本存在SQL注入漏洞,该漏......
  • SeaCMS(海洋CMS)跨站脚本漏洞(CNVD-2024-39583、CVE-2024-44683)
    SeaCMS(海洋CMS)是一款开源免费PHP影视系统,该系统主要被设计用来管理视频点播资源,因其功能强大,操作使用简单,拥有大量用户。 国家信息安全漏洞共享平台于2024-09-29公布其存在跨站脚本漏洞。漏洞编号:CNVD-2024-39583、CVE-2024-44683影响产品:SeaCMS(海洋CMS)13.0漏洞级别:中公布......