【题解】2022ICPC杭州-K

news2024/11/18 20:02:43

翻译

原题链接
在这里插入图片描述
  简述一下就是每次询问重新定义一个字母排序表,问在这个顺序下n个字符串的序列的逆序数是多少。

字典树计算逆序数

  先考虑初始状况下,即 a < b < . . . < z a<b<...<z a<b<...<z的情况下,逆序数如何计算。而对于这种多字符串问题,优先考虑的肯定是字典树,我们可以对所有字符串构建一棵字典树,在字典树的每个节点上记录所有经过它的字符串的下标,然后计算两种情况的逆序数:

  (1) S i S_{i} Si S j S_{j} Sj的前缀,则它们在字典树上的情况一定会在某一个节点 n o d e t node_{t} nodet处满足 i ∈ n o d e t , j ∈ n o d e t i \in node_{t}, j \in node_{t} inodet,jnodet,而 i i i将不会出现在 n o d e t node_{t} nodet的任何子节点上,假如 i > j i > j i>j,那就产生了一组逆序对。我们记这种情况的总逆序数为 A N S 1 ANS_{1} ANS1

  (2) S i S_{i} Si S j S_{j} Sj存在一位不一样的字符,则一定存在一个节点 n o d e t node_{t} nodet,在这里两个字符串走了不同的路,称这两个字符串在这个节点上出现了分歧(后面要用)。于是我们可以遍历每个节点下的两条分支,在这两个分支中跑一遍求逆序数,采用双指针的方式,类似归并排序时求逆序数,复杂度大约为 O ( 13 ∗ 26 ∗ n ) O(13*26*n) O(1326n),记这种情况的总逆序对数为 A N S 2 ANS_{2} ANS2

  于是,答案就是 A N S 1 + A N S 2 ANS_{1}+ANS_{2} ANS1+ANS2

打乱字母表下如何计算逆序数

  那么好,现在考虑字母表排序打乱的情况,上述过程会有什么变化。容易发现,第一种情况不会受到任何影响,仍然是 A N S 1 ANS_{1} ANS1

  对于第二种情况,假如新的顺序变成了 a > b a>b a>b,发现原本因为分歧原因为 a a a b b b的字符串大小关系发生变化,在初始的排序下,我们不再需要它们的逆序对,而是要顺序对。而这种变化会在 a a a b b b大小关系变化时同时发生,可以将所有因此需要调整的地方统一处理。

  思路可能有点抽象,直接上方法。不再直接求 A N S 2 ANS_{2} ANS2,而是两个列表 w 1 [ 26 ] [ 26 ] w_{1}[26][26] w1[26][26] w 2 [ 26 ] [ 26 ] w_{2}[26][26] w2[26][26],其中 w 1 [ c 1 ] [ c 2 ] w1[c_{1}][c_{2}] w1[c1][c2]表示两个字符串因为 c 1 c_{1} c1 c 2 c_{2} c2产生了分歧而产生的顺序对数, w 2 w_{2} w2则是逆序对数,则初始的 A N S 2 ANS2 ANS2其实可以直接表示为:

A N S 2 = ∑ i = 0 25 ∑ j = i + 1 25 w 2 [ i ] [ j ] ANS_{2}=\sum_{i=0}^{25}\sum_{j=i+1}^{25}w_{2}[i][j] ANS2=i=025j=i+125w2[i][j]

  而在新的顺序下,我们设一个数组 w e i g h t [ 26 ] weight[26] weight[26]表示 a a a z z z的权重,则 A N S 2 ANS_{2} ANS2可以表示为:

A N S 2 = ∑ i = 0 25 ∑ j = i + 1 25 w 1 [ i ] [ j ] ∗ ( i f   w e i g h t [ i ] > w e i g h t [ j ] ) ANS_{2}=\sum_{i=0}^{25}\sum_{j=i+1}^{25}w_{1}[i][j]*(if\ weight[i]>weight[j]) ANS2=i=025j=i+125w1[i][j](if weight[i]>weight[j])
             + ∑ i = 0 25 ∑ j = i + 1 25 w 2 [ i ] [ j ] ∗ ( i f   w e i g h t [ i ] < w e i g h t [ j ] ) \ \ \ \ \ \ \ \ \ \ \ \ +\sum_{i=0}^{25}\sum_{j=i+1}^{25}w_{2}[i][j]*(if\ weight[i]<weight[j])             +i=025j=i+125w2[i][j](if weight[i]<weight[j])

  最后别忘了加上 A N S 1 ANS_{1} ANS1

时间复杂度

  建树阶段为 O ( ∑ i = 1 n ∣ S i ∣ ) O(\sum_{i=1}^{n}|S_{i}|) O(i=1nSi)
  求 A N S 1 ANS_{1} ANS1阶段为 O ( ∑ i = 1 n ∣ S i ∣ ) O(\sum_{i=1}^{n}|S_{i}|) O(i=1nSi)
  求 w 1 w_{1} w1 w 2 w_{2} w2阶段为 O ( 13 ∗ 26 ∗ ∑ i = 1 n ∣ S i ∣ ) O(13*26*\sum_{i=1}^{n}|S_{i}|) O(1326i=1nSi)
  回答询问阶段为 O ( 13 ∗ 26 ∗ q ) O(13*26*q) O(1326q)

  注意,上述时间复杂度只是大约,大概率达不到,且中间有一些微微的剪枝优化

  此外,千万不要新建一个vector并用另一个vector给它赋值,只为了弄个新的变量名方便写代码,因为vector赋值是默认 O ( s i z e ) O(size) O(size)一个一个拷贝过去的,而不是指针!!!(因为这个TLE了半天)

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
struct node{
    int nxt[26];
    int value=-1;
    int h;
    vector<int> v;
} G[1000006];
int H[500005];
int new_weight[26];
int szG=1;
int w;     // 子串形成的逆序对数
int w1[26][26], w2[26][26];   // i与j的比较中产生的逆序对数, 反转后产生的逆序对数
int n, q;
inline void ct(int x, int y) {    // 求w1顺序对, w2逆序对
    if(G[x].value > G[y].value) swap(x, y);    // 保证分别为a子树,b子树
    int value1 = G[x].value, value2 = G[y].value;
    int t1 = 0, t2 = 0;
    while(t1 < G[x].v.size() && t2 < G[y].v.size()) {
        if(G[x].v[t1] < G[y].v[t2]) {
            w2[value1][value2] += G[y].v.size() - t2;
            t1 ++;
        } else {
            w1[value1][value2] += G[x].v.size() - t1;
            t2 ++;
        }
    }
}
inline void ct2(int x) {    // 求ANS1,即前缀关系的逆序数
    vector<int> v1, v2;     // 消失的,剩余的
    for(int i=0;i<G[x].v.size();i++) {
        int now = G[x].v[i];
        if(H[now] == G[x].h) {
            v1.push_back(now);
        } else {
            v2.push_back(now);
        }
    }
    int t1 = 0, t2 = 0;
    while(t1 < v1.size() && t2 < v2.size()) {
        if(v1[t1] < v2[t2]) {
            t1 ++;
        } else {
            w += v1.size() - t1;
            t2 ++;
        }
    }
}
inline void dfs(int id) { 
    if(id != 0 && G[id].v.size() <= 1) return;
    for(int i=0;i<26;i++) {
        if(G[id].nxt[i] == 0) continue;
        for(int j=i+1;j<26;j++) {
            if(G[id].nxt[j] == 0) continue;
            ct(G[id].nxt[i], G[id].nxt[j]);
        }
    }
    ct2(id);
    for(int i=0;i<26;i++) {
        if(G[id].nxt[i] == 0) continue;
        dfs(G[id].nxt[i]);
    }
}
signed main() {
    cin>>n>>q;
    for(int i=1;i<=n;i++) {
        string s; cin>>s;
        H[i] = s.length();
        int id = 0;   // 根
        for(int j=0;j<s.size();j++) {
            if(G[id].nxt[s[j]-'a'] == 0) {   // 下一个节点不存在
                G[szG].value = s[j] - 'a';
                G[szG].h = G[id].h + 1;
                G[id].nxt[s[j]-'a'] = szG;
                szG++;
            }
            id = G[id].nxt[s[j]-'a'];
            G[id].v.push_back(i);
        }
    }
    dfs(0);

    while(q--) {           
        string s; cin>>s;
        for(int i=0;i<26;i++) {
            new_weight[s[i]-'a'] = i;
        }
        int sum = 0;
        for(int i=0;i<26;i++) {
            for(int j=i+1;j<26;j++) {
                if(new_weight[i] < new_weight[j])
                    sum += w1[i][j];
                else
                    sum += w2[i][j];
            }
        }
        printf("%lld\n", w + sum);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2175974.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于PI控制器的车辆行驶控制系统simulink建模与仿真

目录 1.课题概述 2.系统仿真结果 3.核心程序与模型 4.系统原理简介 4.1 步骤一: 确定目标与测量 4.2 步骤二: 计算误差 4.3 步骤三: 设计PI控制器 4.4 步骤四: 应用控制信号 4.5 步骤五: 反馈循环 5.完整工程文件 1.课题概述 基于PI控制器的车辆行驶控制系统是一种常…

Hive数仓操作(一)

Hive 介绍 Hive 是一个基于 Hadoop 的数据仓库工具&#xff0c;旨在简化大规模数据集的管理和分析。它将结构化数据文件映射为表&#xff0c;并提供类似 SQL 的查询功能。Hive 的数据存储在 Hadoop 分布式文件系统&#xff08;HDFS&#xff09;中&#xff0c;使用 Hive 查询语…

使用MessagePipe实现进程间通信

1、MessagePipe介绍 可以用于.NET和Unity上面的高性能的内存/分布式消息传递管道。适用于发布/订阅模式、CQRS的中介模式、Prism中的EventAggregator、IPC&#xff08;进程间通信&#xff09;-RPC等。 支持&#xff1a; 依赖注入过滤器管道更好的事件同步/异步带键值的/无键…

信息安全工程师(26)物理安全概念与要求

前言 物理安全是网络安全体系中的重要组成部分&#xff0c;它关注于保护物理环境、设备和资源免受未经授权的访问、破坏、损坏或盗窃。 一、物理安全概念 物理安全&#xff0c;也称为实体安全&#xff0c;是指通过采取各种物理措施来保护支持网络信息系统运行的硬件&#xff08…

【Qt】Qt中的窗口坐标 信号与槽

Qt中的窗口坐标 && 信号与槽 1. Qt中的窗口坐标2. 信号与槽的概述3. 信号和槽的使用3.1 connect函数的使用3.2 查看内置信号和槽3.2 connect的参数类型不匹配问题 4. 自定义信号 && 自定义槽4.1 自定义槽4.2 自定义信号 5. 带参数的信号和槽6. 信号与槽的关联方…

leetcode_55:跳跃游戏

给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输…

C#由窗体原子表溢出造成的软件闪退的问题解决方法

报错信息 由于在MS.Win32.UnsafeNativeMethods.RegisterClassEx产生了报错信息&#xff0c;但是一直向外部抛出错误但始终没有被捕捉成功&#xff0c;直到报错被UI线程捕获&#xff0c;但是仍然没有进行处理&#xff0c;所有造成WPF的应用闪退。 解析报错信息 1.从异常初始位…

Camera Raw:打开图像

在图像工作流程中&#xff0c;无论是 Raw 格式图像文件还是 JPEG、TIFF 文件&#xff0c;都可以先使用 Camera Raw 打开并调整后&#xff0c;再进入其它 Adobe 软件如 Photoshop 中进行进一步的编辑和处理。 一、打开 Raw 格式图像 1、通过 Adobe Bridge 打开 在 Adobe Bridge …

Excel插件:dd统计与排名

Excel插件&#xff1a;dd统计与排名 使用教程 专门为学校成绩统计与排名设计的插件 一、安装后如图 二、 功能介绍&#xff1a; &#xff08;一&#xff09;单科统计与排名 1、 模板说明&#xff08;单科用&#xff09; 2、 单科三分四率统计 PS&#xff1a;可以设置界值&am…

哈希知识点总结:哈希、哈希表、位图、布隆过滤器

目录 哈希 哈希表 哈希常用方法 1、直接定址法 2、存留余数法 哈希冲突 哈希冲突的解决办法 1、闭散列&#xff1a;开放定址法 &#xff08;1&#xff09;线性探测法 &#xff08;2&#xff09;二次探测法 2、开散列 哈希桶 / 拉链法 哈希的运用 位图 set操作 …

07-阿里云镜像仓库

07-阿里云镜像仓库 注册阿里云 先注册一个阿里云账号&#xff1a;https://www.aliyun.com/ 进入容器镜像服务控制台 工作台》容器》容器服务》容器镜像服务 实例列表》个人实例 仓库管理》镜像仓库》命名空间》创建命名空间 仓库管理》镜像仓库》镜像仓库》创建镜像仓库 使…

c++11~c++20 内联命名空间

在工作&#xff0c;我们经常会引入第三方库&#xff0c;偶尔会碰到同名的函数和类型&#xff0c;造成编译冲突的问题。一般我们可以使用命名空间&#xff0c;例如 #include <iostream> #include <iostream> using namespace std;namespace S1 {void foo(){cout &l…

Meta首款多模态Llama 3.2开源:支持图像推理,还有可在手机上运行的版本 | LeetTalk Daily...

“LeetTalk Daily”&#xff0c;每日科技前沿&#xff0c;由LeetTools AI精心筛选&#xff0c;为您带来最新鲜、最具洞察力的科技新闻。 Meta最近推出的Llama Stack的发布标志着一个重要的里程碑。这一新技术的推出不仅为开发者提供了强大的多模态能力&#xff0c;还为企业和初…

重构部队信息安全:部队涉密载体建设新策略

一、完善保密体系架构 1. 加强保密规章制度&#xff1a;制定或刷新关于机密信息管理的相关规定&#xff0c;明确机密信息的生成、复制、传输、使用、储存及销毁等核心环节的操作准则与责任分配&#xff0c;确保整个流程的标准化运作。 2. 明确个人保密义务&#xff1a;通过保密…

古老的啤酒酿造技艺:传承与发扬

在人类文明的浩瀚历史中&#xff0c;啤酒酿造技艺源远流长&#xff0c;承载着世代匠人的智慧与匠心。这些古老的技艺&#xff0c;不仅是一种手艺&#xff0c;更是一种文化的传承。今天&#xff0c;我们将一起走进这神秘的酿造世界&#xff0c;探寻古老啤酒酿造技艺的传承与发扬…

性能调优知识点(mysql)三

SQL底层执行原理 MySQL的内部组件结构&#xff1a;大体来说&#xff0c;MySQL 可以分为 Server 层和存储引擎层store两部分 Server层:主要包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&#xf…

基于Python大数据可视化的民族服饰数据分析系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

基于51单片机的多通道数字电压表proteus仿真

地址&#xff1a;https://pan.baidu.com/s/1zfDI2sjSGFHkYh33Sw6gHQ 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectron…

【数据结构】链表(1)

【概念】 一种物理存储结构上的非连续存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的引用链接次序来实现的 也就是说&#xff0c;链表是由一个一个的节点组织起来的&#xff0c;如车厢一般&#xff0c;整体就叫做链表 【链表结构】 节点可以理解为”节点对象“&#…

详解代理模式-【静态代理与JDK动态代理】(非常的斯国一)

目录 静态代理 什么是静态代理: ​ 特点: 例子&#xff1a; JDK动态代理&#xff08;主要讲点&#xff09; 大纲&#xff1a; 1、与静态代码的联系 2、JDK动态代理的主流程 3、Proxy的源码 整体概述&#xff1a; 重要点的翻译 &#xff1a; newProxyInstance源码&am…