• 字符串基础


    A - Ananagrams

    题意:输入一定量的单词构成词典(区分大小写),从词典中找出符合条件的单词,条件:单词转换成小写字母排序后与词典其他经此操作的单词不同(描述有点乱)。

    Thinking:

    这个题我最开始的感觉是构造hash函数来判重,然后并没有构造(查到)可以操作的函数,再然后就不会做了。网上给出了STL的方法,vector,map和string的排序,很好的解决了这道题的需要。

    还有就是题目所说的lexicographic (case-sensitive) order 应该记下这个定义,这是集合和序的知识,虽然在这里只是基于ASCII排序即可。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <vector>
     4 #include <algorithm>
     5 #include <map>
     6 #include <cctype>
     7 #include <string>
     8 #include <algorithm>
     9 using namespace std;
    10 vector<string> v;
    11 map<string, int> m;
    12 string getlow(const string &x){
    13     string tmp = x;
    14     for(int i=0; i<tmp.size(); i++){
    15         tmp[i] = tolower(tmp[i]);
    16     }
    17     sort(tmp.begin(), tmp.end());
    18     return tmp;
    19 }
    20 int main(){
    21 //    freopen("in.txt", "r", stdin);
    22     string s;
    23     while(cin >> s){
    24         if(s[0] == '#')break;
    25         v.push_back(s);
    26         string tmp = getlow(s);
    27         if(m.count(tmp)==0) m[tmp]=0;
    28         m[tmp]++;
    29     }
    30     vector<string> ans;
    31     for(int i=0; i<v.size(); i++){
    32         if(m[getlow(v[i])] == 1){
    33             ans.push_back(v[i]);
    34         //    cout << v[i] << " ------" << endl;
    35         }
    36     }
    37     sort(ans.begin(), ans.end());
    38     for(int i=0; i<ans.size(); i++){
    39         cout << ans[i] << endl;
    40     }
    41     return 0;
    42 }
    View Code

    从头到尾彻底理解KMP

    C - Number Sequence

    这个KMP(求位置)太明显了,不说了。

     1 #include <cstdio>
     2 #include <string>
     3 #include <cctype>
     4 using namespace std;
     5 const int maxp = 10010, maxt = 1e6+10;
     6 int f[maxp];
     7 int P[maxp], T[maxt];
     8 void getnext(int lenp){
     9     f[0] = f[1] = 0;
    10     for(int i=1; i<lenp; i++){
    11         int j = f[i];
    12         while(j && P[i]!=P[j])  j=f[j];
    13         f[i+1] = P[i]==P[j]? j+1 : 0;
    14     }
    15 }
    16 int kmp(int n, int m){
    17     int cnt = 0, j = 0;
    18     for(int i=0; i<n; i++){
    19         while(j && P[j]!=T[i]){
    20             j = f[j];
    21         }
    22         if(P[j] == T[i])  j++;
    23         if(j == m)  return i-m+1+1; //cnt++
    24     }
    25     return -1;
    26 }
    27 int main(){
    28 //    freopen("in.txt", "r", stdin);
    29     int tt;
    30     scanf("%d", &tt);
    31     while(tt--){
    32         int n, m;
    33         scanf("%d%d", &n, &m);
    34         for(int i=0; i<n; i++){
    35             scanf("%d", &T[i]);
    36         }
    37         for(int i=0; i<m; i++){
    38             scanf("%d", &P[i]);
    39         }
    40         getnext(m);
    41         printf("%d
    ", kmp(n, m));
    42     }
    43     return 0;
    44 }
    View Code

    D - Oulipo 

    这个KMP(计数)太明显了,不说了。

     1 #include <cstdio>
     2 #include <string>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <iostream>
     6 using namespace std;
     7 char p[10010], t[1000010];
     8 int f[10010];
     9 void getnext(){
    10     int m = strlen(p);
    11     f[0]=f[1] = 0;
    12     for(int i=1; i<m; i++){
    13         int j=f[i];
    14         while(j && p[i]!=p[j]) j=f[j];
    15         f[i+1] = p[i]==p[j]?j+1:0;
    16     }
    17 }
    18 int kmp(){
    19     int n = strlen(t), m =strlen(p);
    20     int cnt=0, j=0;
    21     for(int i=0; i<n; i++){
    22         while(j && p[j]!=t[i]) j=f[j];
    23         if(p[j]==t[i]) j++;
    24         if(j==m) cnt++;
    25     }
    26     return cnt;
    27 }
    28 void show()
    29 {
    30     int m=strlen(p);
    31     for(int i=0;i<=m;i++) printf("%4c",p[i]);
    32     putchar('
    ');
    33     for(int i=0;i<=m;i++) printf("%4d",f[i]);
    34     putchar('
    ');
    35 }
    36 int main(){
    37 //    freopen("in.txt", "r", stdin);
    38     int tt;
    39     scanf("%d", &tt);
    40     while(tt--){
    41         scanf("%s", p);
    42         getnext();
    43         scanf("%s", t);
    44         printf("%d
    ", kmp());
    45     }
    46     return 0;
    47 } 
    View Code

    E - Theme Section

    题意:

    有种音乐,音乐用M(10^6)个小写字母表示,主旋律为E,音乐形如EAEBE,计算主旋律E最长可以多长。

    Thinking:

    这道题数据应该是有问题的,我的1A解法肯定是错误的

    题目很好理解,看到这个形式熟悉的EAEBE,以及最长,就想当然的以为是求最大的前后缀匹配(感觉自己脑子有点简单),然后就开始讨论情况,按长度分为两种,然后就谜之默认了中间的E不存在,然后胡搞了下,竟然AC了,开始很高兴,后来去厕所回来的过程中想到了这个中间的E如果小于前后缀匹配的最大值怎么办?

    然后回来构造了个样例 aacsdafrtaa ,果然程序运行的答案错了。

    下面贴出错误code

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 using namespace std;
     8 const int maxn = 1e6+10;
     9 char str[maxn];
    10 int f[maxn];
    11 void getnext(int m){
    12     f[0] = f[1] = 0;
    13     for(int i=1; i<m; i++){
    14         int j = f[i];
    15         while(j && str[i]!=str[j]) j=f[j];
    16         f[i+1] = str[i]==str[j]?j+1:0;
    17     }
    18 }
    19 int main(){
    20 //    freopen("in.txt", "r", stdin);
    21     int n;
    22     scanf("%d", &n);
    23     while(n--){
    24         scanf("%s", str);
    25         int m = strlen(str);
    26         if(m<=2){
    27             printf("0
    ");
    28         }else{
    29             getnext(m);
    30             int tmp = min((int)ceil(m/2.0)-1, f[m]);
    31             //cout << "ceil(m/2) = " << ceil(m/2.0) << endl;
    32             printf("%d
    ", tmp);
    33         }
    34     }
    35     return 0;
    36 }
    37 /*
    38  aacsdafrtaa
    39 */
    View Code

    教训是:思考问题不全面,总想以偷懒的方法做题。

    下面思考正解,其实相比上面的思考,只差一个要解决的问题就是中间的E:沿着next数组,找到字符串非前缀后缀的中间那段是否出现前缀(后缀),这个过程是一个kmp的过程,只要找到即可退出枚举,因为这是沿着next走,即保证长度由大到小。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 using namespace std;
     8 const int maxn = 1e6+10;
     9 char str[maxn];
    10 int f[maxn];
    11 bool vis[maxn];
    12 void getnext(int m){
    13     f[0]=-1;
    14     for(int i=1, j=-1; i<m; i++){
    15         while(j>=0 && str[i]!=str[j+1])  j=f[j];
    16         if(str[j+1]==str[i]) j++;
    17         f[i] = j;
    18     }
    19 }
    20 int kmp(int n, int m){
    21     //n:母串长 从[m-1,n-m] kmp子串 
    22     for(int i=m-1, j=-1; i<n-m; i++){
    23         while(j>=0 && str[j+1]!=str[i]) j=f[j];
    24         if(str[j+1]==str[i]) j++;
    25         if(j+1 == m)  return m;
    26     }
    27     return -1;
    28 }
    29 int main(){
    30     freopen("in.txt", "r", stdin);
    31     int n;
    32     scanf("%d", &n);
    33     while(n--){
    34         scanf("%s", str);
    35         int m = strlen(str);
    36         if(m<=2){
    37             printf("0
    ");
    38         }else{
    39             getnext(m);
    40             /*
    41             for(int i=1; i<=m; i++){
    42                 cout << f[i] << "    ";
    43             }
    44             cout << endl;
    45             */
    46             int j = m-1, tmp=-1;
    47             while(f[j] >= 0){
    48                 int len = kmp(m, f[j]+1);
    49                 if(len > tmp){
    50                     tmp = len;
    51                     break;
    52                 }
    53                 j = f[j];
    54             }
    55             if(tmp==-1) printf("0
    ");
    56             else  printf("%d
    ", tmp);
    57         }
    58     }
    59     return 0;
    60 }
    View Code

    F - Cyclic Nacklace

    题意:题目废话太多,直接从The charmbracelet is made up with那里开始看。向一个字符串加多少字符可以保证全部字符串至少循环2次。

    Thinking:

    next数组找到最大前后缀匹配后即得到循环前缀,然后判断是否已经自循环多次,是否只有一个珍珠(字符),这些情况不用加字符;剩下的情况则通过取余操作去掉一个循环节,即得到剩下存在的字符,即可知要加的字符数。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstring>
     5 #include <string>
     6 #include <algorithm>
     7 using namespace std;
     8 
     9 const int maxn = 100005;
    10 char str[maxn];
    11 int f[maxn];
    12 
    13 void getnext(int m){
    14     f[0] = f[1] = 0;
    15     for(int i=1; i<m; i++){
    16         int j = f[i];
    17         while(j && str[i]!=str[j]){
    18             j = f[j];
    19         }
    20         f[i+1] = str[i]==str[j]?j+1:0;
    21     }
    22 }
    23 int main(){
    24 //    freopen("in.txt", "r", stdin);
    25     int tt;
    26     scanf("%d", &tt);
    27     while(tt--){
    28         scanf("%s", str);
    29         int m = strlen(str);
    30         getnext(m);
    31         /*
    32         for(int i=1; i<=m; i++){
    33             cout << f[i] << "    ";
    34         }
    35         cout << endl;
    36         */
    37         int tmp = m - f[m];
    38         if(m != tmp && m % tmp==0){
    39             printf("0
    ");
    40         }else{
    41             printf("%d
    ", tmp - f[m]%tmp);
    42         }
    43     }
    44     return 0;
    45 }
    View Code

    B - Always an integer

    题意:给定一个形如P/D(P:n的整系数多项式,D是正整数)的多项式,判断它是否在所有正整数处取到整数值。

    这题没做出来,记录下学习心得:

    这里先记一个结论:一个整系数多项式P总是正整数D的倍数的判断依据:把n=1,2,……k+1带入试一遍即可,k是多项式中最高项的次数。

    这里证明训练指南124页很详细,数学归纳+差分数列推出。

    本题还有难点在于字符串的处理,知道数学结论后,写了好久,怎么都写不对。这里参考了一些博客,找到了一种比较好理解的方法,就是通过结构体保存 系数 和 阶数,然后通过字符‘n’和字符'/'将数据分为三类:系数,阶数,除数。得到这些数据后,就利用结论写就好了。

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <map>
     5 #include <string>
     6 #include <cctype>
     7 using namespace std;
     8 #define LL long long
     9 struct D{
    10     LL x, k;
    11 }d[110]; 
    12 int cnt;
    13 LL mu, maxk;
    14 /*
    15  * 模拟时数字和符号分开处理,符号根据情况也分开处理,可以多用参数标记上回合运算的一些情况,并正确更新参数 
    16 */
    17 void build(const string &str){
    18     maxk = mu = 0;
    19     cnt = 0;
    20     LL s=0, a=0, b=0, flag = 1;
    21     int len = str.size();
    22     for(int i=0; i<len; i++){
    23         if(str[i]>='0' && str[i]<='9'){
    24             if(s==0){  // n^符号前的数字 
    25                 a = a*10 + (str[i]-'0');
    26             }else if(s==1){ // n^符号后的数字 
    27                 b = b*10 + (str[i]-'0');
    28             }else if(s==2){  //除号后的数字 
    29                 mu = mu*10 + (str[i]-'0');
    30             }
    31         }else if(str[i]=='/'){
    32             s = 2;
    33         }else if(str[i] == 'n'){
    34             s = 1;
    35         }else if(str[i]==')' || str[i]=='+' || str[i]=='-'){
    36             if(s >= 1){
    37                 if(a==0) a=1;
    38                 if(b==0) b=1;
    39             }
    40             maxk=max(maxk, b);  //保存最大的阶 
    41             d[cnt].x = a * flag;     // k阶对应的系数 
    42             d[cnt].k = b;            // k阶对应的指数 
    43             cnt++;
    44             if(str[i]=='-'){
    45                 flag = -1;
    46             }else if(str[i]=='+'){
    47                 flag = 1;
    48             }
    49             a=b=s=0;
    50         }
    51     }
    52 }
    53 LL pow_(LL a, LL b){
    54     LL ans = 1;
    55     while(b){
    56         if(b&1){
    57             ans = ans * a % mu;
    58         }
    59         b >>= 1;
    60         a = a * a % mu;
    61     }
    62     return ans;
    63 }
    64 bool solve(){
    65     for(LL i=1; i<=maxk+1; i++){
    66         LL ans = 0;
    67         for(int j=0; j<cnt; j++){
    68             ans = (ans + d[j].x * pow_(i, d[j].k)) % mu;
    69         }
    70         if(ans != 0)    return false;
    71     }
    72     return true;
    73 }
    74 int main(){
    75 //    freopen("in.txt", "r", stdin);
    76     string s;
    77     int tt = 0;
    78     while(cin >> s){
    79         //cout << s << endl;
    80         if(s == ".")break;
    81         build(s);
    82         printf("Case %d: %s
    ", ++tt, solve()?"Always an integer":"Not always an integer");
    83     }
    84     return 0;
    85 }
    View Code

    还有很多内容,待补。

  • 相关阅读:
    MySQL基础
    DNS域名解析服务
    仿Mars MP3播放器项目5
    仿Mars MP3播放器项目4
    仿Mars MP3播放器项目3
    仿Mars MP3播放器项目2
    仿Mars MP3播放器项目1
    JAVA 随记1
    Redis和Memcache的区别
    php用smtp发送邮件
  • 原文地址:https://www.cnblogs.com/seaupnice/p/9490775.html
Copyright © 2020-2023  润新知