Codeforces 591B Rebranding

这道题挺考思维的

详解:表一:

-1s1代表的本意abcdefg...
0s1数组的下标和初始值0123456...
1a-b1023456...
2b-c1203456...
3a-d3201456...
4e-g3201654...
5f-a5201634...
6b-b5201634...
7s1数组里面最终包含的值所对应的字符fcabgde...

 表二:

s2数组代表的本意abcdefg...
s2数组的下标0123456...
s2数组里面存的值2315604...
s2数组里面最终包含的值所对应的字符cdbfgae...

 定义两个int类型数组来保存26个英文字母所表示的标号,可以开辟30个空间,s1[30] , s2[30]; 第一次交换ch1='a'与ch2='b' ,就交换s1数组里s1[ch1-'a']与s1[ch2-'a']值,之后的1-6做一样的操作;

肯定会有疑问,为什么要交换s1[ch1-'a']与s1[ch2-'a']的值?交换过后是代表第-1行所表示的字符转换为第7行所表示的字符吗?

其实不是,如果你认为交换过后就是代表“第-1行所表示的字符转换为第7行所表示的字符”是错误的。

每次交换你可以看做   例如:表三:

-1s1代表的本意abcdefg...
0s1数组的下标和初始值0123456...
1a-b1023456...
 数组的值+'a'转换为相应的字符bacdefg...
 其实交换过后代表字符'a'是由字符'b'转化而来字符'b'是由字符'a'转化而来      
2b-c1203456...
 数组的值+'a'转换为相应的字符bcadefg...
  字符'a'是由字符'b'转化而来字符'b'是由字符'c'转化而来字符'c'是由字符'a'转化而来     

 你可以想想是不是这样的;这只是举了两个例子;

也就是说表一的第7行就表示     如表四:

-1s1代表的本意abcdefg......
 s1数组的下标和初始值0123456......
7s1数组里面最终包含的值所对应的字符fcabgde......
 s1数组里面最终的值5201634 
              结论                               字符'a'是由字符'f'转化而来字符'b'是由字符'c'转化而来字符'c'是由字符'a'转化而来字符'd'是由字符'b'转化而来字符'e'是由字符'g'转化而来字符'f'是由字符'd'转化而来字符'g'是由字符'e'转化而来......
              推论                               字符'f'最终转化为'a'字符'c'最终转化为'b'字符'a'最终转化为'c'字符'd'最终转化为'b'字符'g'最终转化为'e'字符'd'最终转化为'f'字符'e'最终转化为'g'......

我们现在已经知道字符最终由哪个字符转化而来,也就是说我们得出的是,知道最终的字符,我们能找到它是由哪个最初的字符转换而来的,之后的怎么办呢? 我们需要转化为 题意给出了最初字符,能找到他最终要转换为哪个字符  这个就要好好思考一下怎么转换了!

其实定义两个数组,可以理解为,s1数组代表字符是由哪个字符转化而来的,s2代表字符最重要转换为哪个字符;

 我们可以观察一下表四:  做这样的处理: 之后就变为表二:

for(i=0; i<26; i++)
     s2[s1[i]]=i;

为什么要这样处理呢?这样处理过后就会简化很多;再加上下面这个步骤,这道题就算是解决了;

for(i=0; i<n; i++)
{
   str[i]=s2[str[i]-'a']+'a';
}

附上代码:

#include<stdio.h>
#define N 2000010

int main()
{
    char str[N], ch1, ch2;
    int s1[30], s2[30];

    int n, m, i, x, y, t;
    while(scanf("%d%d", &n, &m)!=EOF)
    {
        scanf("%s", str);

        for(i=0; i<26; i++)
            s1[i]=i;

        for(i=0; i<m; i++)
        {
            scanf(" %c %c", &ch1, &ch2);

            x=ch1-'a';
            y=ch2-'a';

            t=s1[x];
            s1[x]=s1[y];
            s1[y]=t;
        }

        for(i=0; i<26; i++)
            s2[s1[i]]=i;

        for(i=0; i<n; i++)
        {
            str[i]=s2[str[i]-'a']+'a';
        }
        printf("%s\n", str);
    }
    return 0;
}

  

转载于:https://www.cnblogs.com/wazqWAZQ1/p/4914738.html

下载前可以先看下教程 https://pan.quark.cn/s/a426667488ae 标题“仿淘宝jquery图片左右切换带数字”揭示了这是一个关于运用jQuery技术完成的图片轮播机制,其特色在于具备淘宝在线平台普遍存在的图片切换表现,并且在整个切换环节中会展示当前图片的序列号。 此类功能一般应用于电子商务平台的产品呈现环节,使用户可以便捷地查看多张商品的照片。 说明中的“NULL”表示未提供进一步的信息,但我们可以借助标题来揣摩若干核心的技术要点。 在构建此类功能时,开发者通常会借助以下技术手段:1. **jQuery库**:jQuery是一个应用广泛的JavaScript框架,它简化了HTML文档的遍历、事件管理、动画效果以及Ajax通信。 在此项目中,jQuery将负责处理用户的点击动作(实现左右切换),并且制造流畅的过渡效果。 2. **图片轮播扩展工具**:开发者或许会采用现成的jQuery扩展,例如Slick、Bootstrap Carousel或个性化的轮播函数,以达成图片切换的功能。 这些扩展能够辅助迅速构建功能完善的轮播模块。 3. **即时数字呈现**:展示当前图片的序列号,这需要通过JavaScript或jQuery来追踪并调整。 每当图片切换时,相应的数字也会同步更新。 4. **CSS美化**:为了达成淘宝图片切换的视觉效果,可能需要设计特定的CSS样式,涵盖图片的排列方式、过渡效果、点状指示器等。 CSS3的动画和过渡特性(如`transition`和`animation`)在此过程中扮演关键角色。 5. **事件监测**:运用jQuery的`.on()`方法来监测用户的操作,比如点击左右控制按钮或自动按时间间隔切换。 根据用户的交互,触发相应的函数来执行...
垃圾实例分割数据集 一、基础信息 • 数据集名称:垃圾实例分割数据集 • 图片数量: 训练集:7,000张图片 验证集:426张图片 测试集:644张图片 • 训练集:7,000张图片 • 验证集:426张图片 • 测试集:644张图片 • 分类类别: 垃圾(Sampah) • 垃圾(Sampah) • 标注格式:YOLO格式,包含实例分割的多边形点坐标,适用于实例分割任务。 • 数据格式:图片文件 二、适用场景 • 智能垃圾检测系统开发:数据集支持实例分割任务,帮助构建能够自动识别和分割图像中垃圾区域的AI模型,适用于智能清洁机器人、自动垃圾桶等应用。 • 环境监控与管理:集成到监控系统中,用于实时检测公共区域的垃圾堆积,辅助环境清洁和治理决策。 • 计算机视觉研究:支持实例分割算法的研究和优化,特别是在垃圾识别领域,促进AI在环保方面的创新。 • 教育与实践:可用于高校或培训机构的AI课程,作为实例分割技术的实践数据集,帮助学生理解计算机视觉应用。 三、数据集优势 • 精确的实例分割标注:每个垃圾实例都使用详细的多边形点进行标注,确保分割边界准确,提升模型训练效果。 • 数据多样性:包含多种垃圾物品实例,覆盖不同场景,增强模型的泛化能力和鲁棒性。 • 格式兼容性强:YOLO标注格式易于与主流深度学习框架集成,如YOLO系列、PyTorch等,方便研究人员和开发者使用。 • 实际应用价值:直接针对现实世界的垃圾管理需求,为自动化环保解决方案提供可靠数据支持,具有重要的社会意义。
<think> 题目链接:https://codeforces.com/problemset/problem/519/B 题目大意:给出n个数字,然后给出n-1个数字(第一组),再给出n-2个数字(第二组)。第一组是原数组去掉一个元素,第二组是第一组再去掉一个元素。求被去掉的两个元素(按顺序,即第一个被去掉的是第一个答案,第二个被去掉的是第二个答案)。 方法1:使用求和法 原数组的和为s0,第一组数组的和为s1,则第一个被去掉的数为 s0 - s1。 第二组数组的和为s2,则第二个被去掉的数为 s1 - s2。 方法2:使用排序或哈希表(统计频率) 原数组为a,第一组数组为b,第二组数组为c。 第一个被去掉的元素:在a中出现但不在b中出现的元素,或者在a中比b中多出现一次的元素。 第二个被去掉的元素:在b中出现但不在c中出现的元素,或者在b中比c中多出现一次的元素。 考虑到可能有重复元素,所以使用统计频率的方法更可靠。 具体步骤: 1. 读入原数组a(长度为n),第一组数组b(长度为n-1),第二组数组c(长度为n-2)。 2. 分别统计a、b、c中每个元素的出现频率。 3. 第一个答案:遍历a的元素,找到在a中出现的次数比在b中多一次的元素(或者遍历b的元素,但注意a中可能有b没有的元素,所以遍历a更安全)。 具体:对于a中的每个元素x,如果a中x的频率比b中x的频率大1,则x就是第一个被去掉的。 但注意:因为b中可能没有x,所以当b中不存在x时,b中x的频率为0,此时a中x的频率应该是1(比0大1),所以成立。 4. 第二个答案:同理,遍历b的元素,找到在b中出现的次数比在c中多一次的元素。 但是需要注意:同一个元素可能在数组中出现多次,所以不能只用一个标记,必须统计频率。 另一种方法:由于题目保证答案唯一,我们可以用以下方法: 第一个答案 = 在数组a中出现但在数组b中少出现一次的元素(即a中比b中多一个的元素)。 第二个答案 = 在数组b中出现但在数组c中少出现一次的元素。 实现: 使用map来统计每个数组的元素频率。 但是注意:在统计第二个答案时,我们要在b中找比c中多一次的元素,而b中已经包含第一个答案,所以第一个答案在b中可能比a中少一次,但我们并不关心,因为第二个答案与第一个答案不同。 步骤: 1. 读入n,然后读入三个数组。 2. 分别用三个map统计a, b, c中每个元素的频率。 3. 遍历a中的每个元素,对于每个元素x,如果freq_a[x] != freq_b[x](实际上应该大1),则第一个答案就是x,并跳出(但注意可能有多个?题目保证唯一,所以找到一个即可?但是因为同一个元素出现多次,我们只需找到一个元素在a中频率比b中多1即可,但这样的元素只有一个,因为只去掉一个元素,所以整个数组a中只有一个元素会多一次。但实际上,如果有重复元素,那么可能有多个元素在a中的频率比b中多1?但是仔细分析:只去掉一个元素,所以整个数组a和b之间,只有被去掉的那个元素在a中的频率比b中多1,其他元素都相同。所以我们可以遍历a,找到第一个满足freq_a[x] > freq_b[x]的元素,然后输出并跳出?但是有可能这个元素在b中不存在,所以用freq_b[x]可能为0。 具体:我们可以这样: for (auto x: a) { if (freq_a[x] - freq_b[x] == 1) { first = x; break; } } 但是注意:在遍历时,同一个x可能出现多次,所以不能一找到就break,因为可能后面还有?不对,因为同一个x,我们通过频率比较,如果这个x在a中出现了k次,那么在b中出现了k-1次,那么当我们遍历到x时,就会满足条件。但是这样会多次检测到同一个x,所以我们可以记录下这个x,然后跳出循环?但是这样会重复记录同一个x多次。因此,我们可以遍历map,而不是遍历数组a。 改进:遍历频率映射: for (auto it : freq_a) { int x = it.first; if (it.second - freq_b[x] == 1) { first = x; break; } } 但是这里要注意:freq_b中可能没有x,所以我们需要检查x是否在freq_b中?或者我们初始化freq_b时,对于a中所有元素都初始化了?没有。所以我们可以这样:使用map的find方法,或者直接访问freq_b[x],如果x不在freq_b中,则返回0(因为我们使用map,默认值0)。 同样,第二个答案:遍历freq_b,找freq_b[x] - freq_c[x] == 1的元素。 但是注意:第一个答案也可能在b中出现(在c中不出现)吗?第二个答案只与b和c有关,所以这样找没有问题。 但是:第一个答案被去掉后,在b中就不存在了?不对,b是去掉第一个答案后的数组,所以第一个答案在b中出现的次数应该比a中少1(如果a中出现了多次,那么b中只少一次)。所以我们的方法正确。 但是:如果a中有重复元素,比如a=[2,2,3],b=[2,3],那么第一个被去掉的是2。那么freq_a[2]=2,freq_b[2]=1,所以2满足条件。而其他元素(3)在a和b中频率相等。 所以我们可以使用频率差的方法。 步骤: 1. 读入n,然后读入数组a(n个数),数组b(n-1个数),数组c(n-2个数)。 2. 定义三个map:freq_a, freq_b, freq_c。 3. 统计a中每个元素的频率,b中每个元素的频率,c中每个元素的频率。 4. 遍历freq_a,找到第一个满足 freq_a[x] - (freq_b.count(x)?freq_b[x]:0) == 1 的x,作为第一个答案。 5. 遍历freq_b,找到第一个满足 freq_b[x] - (freq_c.count(x)?freq_c[x]:0) == 1 的x,作为第二个答案。 但是注意:第一个答案可能有多个元素满足条件吗?题目保证唯一,所以只有一个元素会被去掉,所以只有一个元素满足这个条件。因此,我们找到第一个满足条件的x即可(但map遍历是随机的,所以最好直接遍历,然后输出找到的第一个,因为只有一个)。 但是,我们也可以不用map遍历,而是遍历数组a(但数组a有重复,所以可能重复找到同一个元素多次)。所以还是遍历map比较好。 但是注意:题目要求按顺序输出:先输出的第一个被去掉的,再输出第二个被去掉的。 所以,我们也可以这样: 第一个答案:遍历a,直到找到一个元素x,使得freq_a[x] > freq_b[x](并且我们每找到一个,就在freq_b[x]上加1?这样不行)。所以还是用map统计后直接查找。 代码实现: 注意:由于n最大10^5,所以用map统计不会超时(O(n log n))。 另外:也可以使用unordered_map(平均O(n))。 代码: 方法1:使用map(或unordered_map)统计频率。 但是:题目要求按顺序输出两个答案,所以先输出第一个被去掉的,再输出第二个。 步骤: 1. 读入数组a,b,c。 2. 统计频率: map<int, int> fa, fb, fc; for (int i=0; i<n; i++) fa[a[i]]++; for (int i=0; i<n-1; i++) fb[b[i]]++; for (int i=0; i<n-2; i++) fc[c[i]]++; 3. 然后: int first = 0, second = 0; for (auto it : fa) { int num = it.first; if (it.second != fb[num]) { // 因为只少一个,所以一定是fa[num] == fb[num] + 1 first = num; break; // 因为只有一个,所以找到就可以退出 } } for (auto it : fb) { int num = it.first; if (it.second != fc[num]) { second = num; break; } } 4. 输出 first 和 second。 但是,注意:在第一个循环中,我们遍历fa,然后比较fa[num]和fb[num](如果num不在fb中,fb[num]默认0)。但是当fa[num]不等于fb[num]时,我们直接取num作为第一个答案并跳出。因为只少一个元素,所以这样的元素只有一个。 但是:在第二个循环中,同样遍历fb,然后比较fb[num]和fc[num](如果num不在fc中,则fc[num]为0)。 但是:有没有可能第一个循环中,有多个元素满足fa[num]!=fb[num]?题目保证答案唯一,所以只有一个元素被去掉,所以只有一个元素满足fa[num]!=fb[num](即fa[num]比fb[num]大1,而其他都相等)。 但是,我们这样写可能会遇到问题:如果一个元素在a中不存在,但在fa中不会出现(因为我们遍历fa,所以不会出现这种情况)。所以正确。 但是:如果第一个答案在a中只出现一次,那么fb中这个元素就不存在(即fb[num]为0),此时fa[num]=1,fb[num]=0,满足不等。 所以,这个方法正确。 但是,有一个小问题:遍历map时,我们不知道顺序,但题目不要求顺序,只要输出那个被去掉的元素即可(因为答案唯一),所以任意顺序遍历map都可以。 但是,我们也可以不用map,而用数组求和法(更简单,且O(n)): long long s1 = 0, s2 = 0, s3 = 0; for (int i=0; i<n; i++) s1 += a[i]; for (int i=0; i<n-1; i++) s2 += b[i]; for (int i=0; i<n-2; i++) s3 += c[i]; int first = s1 - s2; int second = s2 - s3; 求和法更简单,且效率高(O(n)),但要注意数据范围:n最大10^5,元素最大10^9,那么s1最大10^14,所以用long long不会溢出(long long最大9e18)。 所以,推荐使用求和法。 但是,求和法有一个问题:如果数组中有重复元素,并且被去掉的元素是重复的,会不会影响?不会,因为求和法就是计算总和,去掉一个元素,那么两个数组的差就是这个元素。 所以,求和法完全正确。 因此,我们可以写两种方法,但这里推荐求和法(更简单高效)。 代码(求和法): #include <iostream> using namespace std; int main() { int n; cin >> n; long long a_sum = 0, b_sum = 0, c_sum = 0; int x; for (int i = 0; i < n; i++) { cin >> x; a_sum += x; } for (int i = 0; i < n-1; i++) { cin >> x; b_sum += x; } for (int i = 0; i < n-2; i++) { cin >> x; c_sum += x; } long long first = a_sum - b_sum; long long second = b_sum - c_sum; cout << first << endl; cout << second << endl; return 0; } 但是,题目要求输出两个答案,第一个答案和第二个答案。 但是,有没有可能多个不同的元素被去掉,但是和相同?题目没有说元素互不相同,所以有可能出现两个不同的元素和相同吗?题目要求去掉两个元素(但这两个元素可能相同),但是注意:在第一个数组中,去掉一个元素后得到第二个数组,再去掉一个元素得到第三个数组。所以两个被去掉的元素可能是相同的。 但是,用求和法:第一个答案 = a_sum - b_sum,第二个答案 = b_sum - c_sum。 如果两个被去掉的元素相同,比如a_sum - b_sum = X,b_sum - c_sum = X,那么输出两个X。 所以,求和法完全正确。 但是,题目中是否有说明元素互不相同?没有,所以可能重复。 因此,我们使用求和法。 但是,注意:题目要求输入输出格式,以及多个测试用例?看题目描述:输入第一行是n,然后第二行是n个整数(原数组),第三行是n-1个整数(第一组),第四行是n-2个整数(第二组)。 所以,我们只需要读入一次。 但是,题目中可能有多个测试用例?不,题目描述:The first line contains integer n (3≤n≤10^5) — the initial length of the array. 所以只有一个测试用例。 但是,我们再看题目:Input中第一行是n,所以代码按单组输入。 所以,最终代码: 注意:使用long long,因为元素最大10^9,n最大10^5,总和最大10^14。 代码: </think> 对于 Codeforces 519B 问题,我将提供两种优化解法:**求和法**(推荐)和**频率统计法**。原始问题需要找出两次删除操作中被移除的元素。 ### 解法一:求和法(O(n) 时间复杂度) 这是最优解法,利用数组和的差值直接计算被移除的元素: ```cpp #include <iostream> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; long long a_sum = 0, b_sum = 0, c_sum = 0; int x; // 读取原始数组并求和 for (int i = 0; i < n; i++) { cin >> x; a_sum += x; } // 读取第一次删除后的数组并求和 for (int i = 0; i < n - 1; i++) { cin >> x; b_sum += x; } // 读取第二次删除后的数组并求和 for (int i = 0; i < n - 2; i++) { cin >> x; c_sum += x; } // 计算被移除的元素 long long first_removed = a_sum - b_sum; long long second_removed = b_sum - c_sum; cout << first_removed << "\n"; cout << second_removed << "\n"; return 0; } ``` #### 代码解释: 1. **输入处理**: - 读取数组大小 `n` - 使用 `long long` 防止总和溢出(元素值 ≤10⁹,n≤10⁵,总和最大 10¹⁴) 2. **求和计算**: - `a_sum`:原始数组总和 - `b_sum`:第一次删除后数组(n-1 个元素)总和 - `c_sum`:第二次删除后数组(n-2 个元素)总和 3. **差值计算**: - `first_removed = a_sum - b_sum`:第一个被删除的元素 - `second_removed = b_sum - c_sum`:第二个被删除的元素 4. **时间复杂度**:O(n),仅需三次线性遍历 ### 解法二:频率统计法(O(n log n) 时间复杂度) 使用哈希表统计元素频率,适合元素值范围大的情况: ```cpp #include <iostream> #include <vector> #include <unordered_map> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; cin >> n; vector<int> a(n), b(n-1), c(n-2); unordered_map<int, int> freq_a, freq_b, freq_c; // 读取并统计原始数组频率 for (int i = 0; i < n; i++) { cin >> a[i]; freq_a[a[i]]++; } // 读取并统计第一次删除后数组频率 for (int i = 0; i < n - 1; i++) { cin >> b[i]; freq_b[b[i]]++; } // 读取并统计第二次删除后数组频率 for (int i = 0; i < n - 2; i++) { cin >> c[i]; freq_c[c[i]]++; } // 查找第一个被删除的元素 int first_removed = 0; for (int num : a) { if (freq_a[num] != freq_b[num]) { first_removed = num; break; } } // 查找第二个被删除的元素 int second_removed = 0; for (int num : b) { if (freq_b[num] != freq_c[num]) { second_removed = num; break; } } cout << first_removed << "\n"; cout << second_removed << "\n"; return 0; } ``` #### 代码解释: 1. **数据结构**: - 使用 `unordered_map` 存储元素频率(平均 O(1) 操作) - `vector` 存储输入数组 2. **频率统计**: - `freq_a`:原始数组频率 - `freq_b`:第一次删除后频率 - `freq_c`:第二次删除后频率 3. **查找被删元素**: - 第一个元素:在 `a` 中频率比 `b` 大 1 的元素 - 第二个元素:在 `b` 中频率比 `c` 大 1 的元素 4. **时间复杂度**:O(n log n)(哈希表操作均摊 O(1)) ### 两种解法对比 | 特性 | 求和法 | 频率统计法 | |--------------|---------------------------|--------------------------| | 时间复杂度 | O(n) | O(n)(均摊) | | 空间复杂度 | O(1) | O(n) | | 适用场景 | 推荐通用解法 | 元素范围极大时更稳定 | | 优势 | 代码简洁,内存占用少 | 不依赖数值计算 | | 注意事项 | 总和可能溢出(用long long)| 哈希冲突可能影响性能 | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值