zoukankan      html  css  js  c++  java
  • Rebranding[Codeforces 591B]

    Rebranding(CodeForces 591B)

    Codeforces Round #327 (Div. 2) Time:2000ms Memory:256MB

    这道题主要是模拟字符串序列操作。最简单的办法便是直接对整个字符串进行操作,然而题目中字符串的长度$m$的最大取值为$200000$,最多可能的操作次数$n$的最大取值也是$200000$,因此$O(mn)$的时间复杂度是会超时的。(事实是确实有这么变态的数据,一开始fgets 200000长度都RE了)

    从另一个角度考虑这个问题,在每一次操作过程当中,只是将对应的字母整体作了变换操作。

    以第二个样例的第一次操作为例:

    abacabadaba
    其进行a b操作后,变为

    babcbabdbab可以观察到原先的a位置全部变为b,原先的b全部变为了a,因此可以存储每个字母对应的下标位置,进行操作时a b时,就可以转化为将原先a指向a替换为a指向bb指向b替换为b指向a。后续操作是建立在当前操作的基础之上,当前操作是正确的,利用循环不变式不难证明整个过程也是正确的,这里略去不证。

    因此我在这里用一个队列数组保存每个字母对应的出现位置,每当扫进一个字母时,根据字母的对应关系将其进入相应的队列,从而在最终进行操作时,只是将队列的指针发生了移动,因而提高了效率,最后依据序号逐次将字母输出即可。该方法整体的时间复杂度为$O(m+n)$(初始化队列和队列输出中的第二层循环的贡献都可以看作是常数$k=26$,可略去),明显优于$O(mn)$的方法。

    后来查阅CF题解时,我的大体思路是正确的,只是他用str数组来实现计算偏移代码实现更简洁,少了队列本身扩张的常数时间开销(队列的ENQUEUE和DEQUEUE都是$O(1)$时间的,因此对整个复杂度没有影响,但是内存分配确实会影响性能,好在STL采用多层分配器来实现,性能确实没有想象的那么差。)。

    我的C++实现如下:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<queue>
     4 using namespace std;
     5 char str[200006];
     6 queue<int> * mapper[30];
     7 int main()
     8 {
     9     for (int m = 0; m < 26; m++)
    10         mapper[m] = new queue<int>;
    11     int len, T;
    12     cin >> len >> T;
    13     getchar();
    14     fgets(str, 200005, stdin);
    15     for (int i = 0; i < len; i++)
    16         mapper[str[i] - 'a']->push(i);
    17     while (T--)
    18     {
    19         char a, b;
    20         scanf("
    %c %c", &a, &b);
    21         if (a == b)continue;
    22         queue<int> * tmpptr = mapper[b - 'a'];
    23         mapper[b - 'a'] = mapper[a - 'a'];
    24         mapper[a - 'a'] = tmpptr;
    25     }
    26     for (int i = 0; i < len; i++)
    27         for (int j = 0; j < 26; j++)
    28         {
    29             if (mapper[j]->empty() == false)
    30             {
    31                 if (mapper[j]->front() == i)
    32                 {
    33                     putchar(j + 'a');
    34                     mapper[j]->pop();
    35                     break;
    36                 }
    37             }
    38         }
    39     return 0;
    40 }

    CF给的标程实现如下:

     1 #include <bits/stdc++.h>
     2 #define fi first
     3 #define sc second
     4 using namespace std;
     5 typedef pair<int,int> pi;
     6 char s[300009];
     7 char ch[30];
     8 int main(){
     9     int n,m;scanf("%d%d",&n,&m);
    10     scanf("%s",s);
    11     for(int i=0;i<26;i++)ch[i]=i+'a';
    12     for(int i=0;i<m;i++){
    13         char a,b;scanf(" %c %c",&a,&b);
    14         for(int j=0;j<26;j++){
    15             if(ch[j]==a)ch[j]=b;
    16             else if(ch[j]==b)ch[j]=a;
    17         }
    18     }
    19     for(int i=0;i<n;i++){
    20         printf("%c",ch[s[i]-'a']);
    21     }
    22 }
  • 相关阅读:
    三级联动(在YII框架中)
    用composer安装Yii
    在apache中设置访问目录后进入的默认页面为index.php
    php mb_convert_encoding的使用
    采集数据和memchche的存储使用,分页展示
    php操作Memcache
    前端页面卡顿?或是DOM操作惹的祸,需优化代码
    windows mongodb 安装
    浅谈WebSocket
    使用Spring MVC HandlerExceptionResolver处理异常
  • 原文地址:https://www.cnblogs.com/ggggg63/p/6725232.html
Copyright © 2011-2022 走看看