P1624 单词缩写

题目描述

树树发现好多计算机中的单词都是缩写,如GDB是全称Gnu DeBug的缩写。但是,有时候缩写对应的全称会不固定,如缩写LINUX可以理解为:

(1) LINus’s UniX

(2) LINUs’s miniX

(3) Linux Is Not UniX

现在树树给出一个单词缩写,以及一个固定的全称(若干个单词组成,空格隔开)。全

称中可能会有无效的单词,需要忽略掉,一个合法缩写要求每个有效单词中至少有一个字符出现在缩写中,所写必须按顺序出现在全称中。

对于给定的缩写和一个固定的全称,问有多少种解释方法?解释方法为所写的每个字母在全称每个有效单词中出现的位置,有一个字母位置不同,就认为是不同的解释方法。

输入输出格式

输入格式:

第一行输入一个N,表示有N个无效单词;

接下来N行分别描述一个由小写字母组成的无效单词;

最后是若干个询问,先给出缩写(只有大写字母),然后给出一个全称,读入以“LAST CASE”结束。

[数据规模]

1≤N≤100,每行字符串长度不超过150,询问次数不超过20,最后方案数不超过10^9。

输出格式:

对于每个询问先输出缩写,如果当前缩写不合法,则输出“is not a valid abbreviation”,否则输出“can be formaed in i ways”(i表示解释方法数)

输入输出样例

输入样例#1: 复制

  1. 2
  2. and
  3. of
  4. ACM academy of computer makers
  5. RADAR radio detection and ranging
  6. LAST CASE
输出样例#1: 复制

  1. ACM can be formed in 2 ways
  2. RADAR is not a valid abbreviation

洛谷题解

先暴力去掉所有的单词,只对有效单词进行计算。

dp[i][j]表示前i个单词使用了前j个大写字母的方案数

初始条件dp[0][0]=1

转移:若第i个单词使用第j到第j+k个大写字母的方案数为temp[k]

则dp[i][j+k]=dp[i-1][j-1]*temp[k]

最终ans=dp[n][m]

时间复杂度O(L1*N*L2*L2)

空间复杂度O(L1*N*L2)

L1缩写长度 N全称中单词的个数 L2全称中一个单词的长度

这属于两个串匹配的问题,就一个前i,一个前j就好,反正是找子问题。

  1. #include<cstdio>
  2. #include<iostream>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. char w[][];
  7. char s[],let[];
  8. char over[]={'L','A','S','T',' ','C','A','S','E'};
  9. struct word
  10. {
  11. char c[];
  12. int l;
  13. }a[];
  14. int t,n,m,len;
  15. int dp[][],temp[];
  16. bool Case_is_Over()
  17. {
  18. for (int i=;i<=;i++)
  19. if (s[i]!=over[i]) return false;
  20. return true;
  21. }
  22. int main()
  23. {
  24. freopen("abbr.in","r",stdin);
  25. freopen("abbr.out","w",stdout);
  26. scanf("%d\n",&t);
  27. for (int i=;i<=t;i++) scanf("%s",w[i]);
  28. while ()
  29. {
  30. char ch=getchar();len=;
  31. while ( ! ( (ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z') || ch==' ' ) ) ch=getchar();
  32. while ( (ch>='a'&&ch<='z') || (ch>='A'&&ch<='Z') || ch==' ' ) s[len++]=ch,ch=getchar();
  33. n=m=;//设每个询问有n个单词,m个大写字母
  34. if (Case_is_Over()) break;
  35. int p=;
  36. for (int i=;i<;i++) memset(a[i].c,,sizeof(a[i].c)),a[i].l=;
  37. while (s[p]>='A'&&s[p]<='Z')
  38. {
  39. printf("%c",s[p]);
  40. let[++m]=s[p]+;
  41. p++;
  42. }
  43. p++;
  44. while (p<len)
  45. {
  46. n++;
  47. while (s[p]>='a'&&s[p]<='z')
  48. {
  49. a[n].c[a[n].l++]=s[p];
  50. p++;
  51. }
  52. for (int i=;i<=t;i++)
  53. if (strcmp(w[i],a[n].c)==)
  54. {
  55. memset(a[n].c,,sizeof(a[n].c));
  56. a[n].l=;
  57. n--;break;
  58. }
  59. p++;
  60. }
  61. memset(dp,,sizeof(dp));
  62. dp[][]=;
  63. for (int i=;i<=n;i++) //枚举单词
  64. for (int j=i;j<=i+m-n;j++) //枚举当前单词使用大写字母的起始位置
  65. {
  66. memset(temp,,sizeof(temp));
  67. for (int p=;p<a[i].l;p++) //第i个单词的第p个位置
  68. for (int k=min(i+m-n-j,p);k>=;k--) //恰好等于第j+k个大写字母
  69. if (let[j+k]==a[i].c[p])
  70. if (k) temp[k]+=temp[k-];
  71. else temp[k]++;
  72. for (int k=i+m-n-j;k>=;k--)
  73. dp[i][j+k]+=dp[i-][j-]*temp[k];
  74. }
  75. if (dp[n][m]) printf(" can be formed in %d ways\n",dp[n][m]);
  76. else printf(" is not a valid abbreviation\n");
  77. }
  78. return ;
  79. }

看大家都是N^4或N³算法,N²算法还没有,赶紧水一发

基本思路:

把所有串连接起来,记录每个串的尾后位置,

设f[k][i]表示现在在处理缩写的第K个字符,在大字符串中第I个位置对前面字符的总贡献数,则f[k][i]=Σf[k-1][j],

其中j表示满足条件的前一个缩写字符。其中满足条件的定义为“无空缺单词,且是前一个字母”。则答案为Σf[最后一个字符][j],(1<=j<=n)。

为避免出现同一字母出现位置的不同,用一个数组进行标记即可。

标记要一次打完才能更新!!!

  1. #include<bits/stdc++.h>
  2. #define RG register
  3. using namespace std;
  4.  
  5. int n;
  6. char a[][];//无效单词
  7. char c1[];
  8. char c[];
  9. char all[][];//有效单词
  10. int ma[][];//每个字母的有效位置
  11. int tag[];
  12. int tag1[];//两个标记
  13. int cut[];//单词的尾后位置
  14. int sum[];//出现的次数
  15. int f[][];//dp数组
  16.  
  17. int main()
  18. {
  19. scanf("%d\n",&n);
  20. for(RG int i=;i<=n;i++)
  21. {
  22. scanf("%s",a[i]);
  23. }
  24. scanf("%s",c1);
  25. while()
  26. {
  27. RG int i_1_1=;
  28. strcpy(c,c1);
  29. if(strcmp(c,"LAST")==)
  30. {
  31. scanf("%s",all[i_1_1++]);
  32. if(strcmp(all[i_1_1-],"CASE")==) break;
  33. }
  34. while(cin>>all[i_1_1++])
  35. {
  36. RG int j=;
  37. int len=strlen(all[i_1_1-]);
  38. while(all[i_1_1-][j]<'a'&&j<len) j++;
  39. if(j>=len)
  40. {
  41. strcpy(c1,all[i_1_1-]);
  42. i_1_1--;
  43. break;
  44. }
  45. else
  46. {
  47. for(RG int i=;i<=n;i++)
  48. {
  49. if(strcmp(a[i],all[i_1_1-])==)
  50. {
  51. i_1_1--;
  52. break;
  53. }
  54. }
  55. }
  56. }
  57. i_1_1--;
  58. printf("%s ",c);
  59. int len=strlen(c);
  60. for(RG int i=;i<len;i++)
  61. {
  62. c[i]=c[i]+;
  63. }
  64. //读入
  65. if(len<i_1_1)//分类讨论
  66. {
  67. puts("is not a valid abbreviation");
  68. }
  69. else if(len==i_1_1)
  70. {
  71. int ans=;
  72. for(RG int i=;i<len;i++)
  73. {
  74. int len2=strlen(all[i+]);
  75. RG int tmp=;
  76. for(RG int j=;j<len2;j++)
  77. {
  78. if(all[i+][j]==c[i]) tmp++;
  79. }
  80. if(tmp) ans*=tmp;
  81. else
  82. {
  83. puts("is not a valid abbreviation");
  84. break;
  85. }
  86. }
  87. printf("can be formed in %d ways\n",ans);
  88. }
  89. else //重点
  90. {
  91. memset(sum,,sizeof(sum));
  92. memset(f,,sizeof(f));
  93. memset(tag,,sizeof(tag));
  94. memset(cut,,sizeof(cut));
  95. memset(ma,,sizeof(ma));
  96. int cz=strlen(all[]);
  97. for(int i=;i<=i_1_1;i++)
  98. {
  99. strcpy(all[]+cz,all[i]);
  100. cut[i-]=cz;
  101. cz=strlen(all[]);
  102. }
  103. //连串
  104. cut[i_1_1]=cz;
  105. for(int i=;i<cz;i++)
  106. {
  107. int j=all[][i]-'a';
  108. ma[j][++sum[j]]=i;
  109. }
  110. //记字母位置
  111. for(int k=;k<len;k++)
  112. {
  113. int id=c[k]-'a';
  114. int ci=min(k+,i_1_1);
  115. int ti=;
  116. for(int i=;i<cz;i++)
  117. {
  118. tag1[i]=tag[i];
  119. }//备份
  120. for(int i=;i<=sum[id]&&ma[id][i]<cut[ci];i++)
  121. {
  122. while(ma[id][i]>=cut[ti]) ti++;
  123. if(i_1_1-ti>len-k-) continue;
  124. if(k==)
  125. {
  126. tag1[ma[id][i]]=;//标记
  127. f[k][i]=;//初始值
  128. }
  129. else
  130. {
  131. int t=c[k-]-'a';
  132. for(int j=;j<=sum[t];j++)
  133. {
  134. if(ma[t][j]<ma[id][i]&&ma[t][j]>=cut[ti-]&&tag[ma[t][j]]==k-)
  135. {
  136. f[k][i]+=f[k-][j];//转移
  137. tag1[ma[id][i]]=k;//标记×2
  138. }
  139. }
  140. }
  141. }
  142. for(int i=;i<cz;i++)
  143. {
  144. tag[i]=tag1[i];//备份
  145. }
  146. }
  147. int ans=;
  148. for(int i=;i<=sum[c[len-]-'a'];i++)
  149. {
  150. ans+=f[len-][i];//求和
  151. }
  152. if(ans)
  153. {
  154. printf("can be formed in %d ways\n",ans);
  155. }
  156. else puts("is not a valid abbreviation");
  157. }
  158. }
  159. return ;
  160. }

P1624 单词缩写的更多相关文章

  1. [LeetCode] Minimum Unique Word Abbreviation 最短的独一无二的单词缩写

    A string such as "word" contains the following abbreviations: ["word", "1or ...

  2. [LeetCode] Valid Word Abbreviation 验证单词缩写

    Given a non-empty string s and an abbreviation abbr, return whether the string matches with the give ...

  3. [LeetCode] Unique Word Abbreviation 独特的单词缩写

    An abbreviation of a word follows the form <first letter><number><last letter>. Be ...

  4. 单词缩写(abbr.cpp)每日一题

    题目描述:YXY 发现好多计算机中的单词都是缩写,如 GDB,它是全称 Gnu DeBug 的缩写.但是,有时缩写对应的全称并不固定,如缩写 LINUX,可以理解为:(1)LINus's UniX ( ...

  5. [LeetCode] Word Abbreviation 单词缩写

    Given an array of n distinct non-empty strings, you need to generate minimal possible abbreviations ...

  6. [Swift]LeetCode288. 唯一单词缩写 $ Unique Word Abbreviation

    An abbreviation of a word follows the form <first letter><number><last letter>. Be ...

  7. [LeetCode] 527. Word Abbreviation 单词缩写

    Given an array of n distinct non-empty strings, you need to generate minimal possible abbreviations ...

  8. [LeetCode] 288.Unique Word Abbreviation 独特的单词缩写

    An abbreviation of a word follows the form <first letter><number><last letter>. Be ...

  9. HDOJ/HDU 2564 词组缩写(单词缩写)

    Problem Description 定义:一个词组中每个单词的首字母的大写组合称为该词组的缩写. 比如,C语言里常用的EOF就是end of file的缩写. Input 输入的第一行是一个整数T ...

随机推荐

  1. Vue学习笔记【14】——自定义指令

    1.自定义全局和局部(私有)自定义指令 // 自定义全局指令 v-focus,为绑定的元素自动获取焦点: ​ Vue.directive('focus', { ​ inserted: function ...

  2. obj.offsetHeight与obj.style.height $(obj).height()与$(obj).css('height')

    相同:都可以获取obj的高度区别:(1)obj.offsetHeight可以获取外部.内嵌和内联中定义的高,而obj.style.height只能获取内联中定义的高:(2)obj.offsetHeig ...

  3. 最大流EK和Dinic算法

    最大流EK和Dinic算法 EK算法 最朴素的求最大流的算法. 做法:不停的寻找增广路,直到找不到为止 代码如下: @Frosero #include <cstdio> #include ...

  4. VMware Network Adapter VMnet1/8详解

    转自:https://www.cnblogs.com/systemnet123/articles/2640883.html VMWare提供了三种工作模式,它们是bridged(桥接模式).NAT(网 ...

  5. 炼数成金数据分析课程---14、Logistic回归

    炼数成金数据分析课程---14.Logistic回归 一.总结 一句话总结: 大纲+实例快速学习法 主要讲Logistic回归的原理及编程实现 1.事件的优势比(odds)是什么? 记y取1的概率是p ...

  6. 转-C++之虚函数不能定义成内联函数的原因

    转自:https://blog.csdn.net/flydreamforever/article/details/61429140 在C++中,inline关键字和virtual关键字分别用来定义c+ ...

  7. CSS:CSS 简介

    ylbtech-CSS:CSS 简介 1.返回顶部 1. CSS 简介 你需要具备的知识 在继续学习之前,你需要对下面的知识有基本的了解: HTML / XHTML 如果你希望首先学习这些项目,请在  ...

  8. java发带图片正文和附件的邮件mail

    package com.mail; import java.io.UnsupportedEncodingException; import java.util.Date; import java.ut ...

  9. C++——代码风格

    google代码风格 1.使用安全的分配器(allocator),如scoped_ptr,scoped_array 2.测试用的,其他的不能用: 2.1 友元 2.2 C++异常 2.3 RTTI 3 ...

  10. HDU 6667 Roundgod and Milk Tea (思维)

    2019 杭电多校 8 1011 题目链接:HDU 6667 比赛链接:2019 Multi-University Training Contest 8 Problem Description Rou ...