标签:答案 inux enter badge 长度 cut += cti 理解
树树发现好多计算机中的单词都是缩写,如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表示解释方法数)
2 and of ACM academy of computer makers RADAR radio detection and ranging LAST CASE
ACM can be formed in 2 ways RADAR is not a valid abbreviation
洛谷题解
看大家都是N^4或N3算法,N2算法还没有,赶紧水一发
基本思路:
把所有串连接起来,记录每个串的尾后位置,
设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[110][200];//无效单词 7 char c1[200]; 8 char c[200]; 9 char all[200][200];//有效单词 10 int ma[26][200];//每个字母的有效位置 11 int tag[200]; 12 int tag1[200];//两个标记 13 int cut[200];//单词的尾后位置 14 int sum[26];//出现的次数 15 int f[200][200];//dp数组 16 17 int main() 18 { 19 scanf("%d\n",&n); 20 for(RG int i=1;i<=n;i++) 21 { 22 scanf("%s",a[i]); 23 } 24 scanf("%s",c1); 25 while(1) 26 { 27 RG int i_1_1=1; 28 strcpy(c,c1); 29 if(strcmp(c,"LAST")==0) 30 { 31 scanf("%s",all[i_1_1++]); 32 if(strcmp(all[i_1_1-1],"CASE")==0) break; 33 } 34 while(cin>>all[i_1_1++]) 35 { 36 RG int j=0; 37 int len=strlen(all[i_1_1-1]); 38 while(all[i_1_1-1][j]<‘a‘&&j<len) j++; 39 if(j>=len) 40 { 41 strcpy(c1,all[i_1_1-1]); 42 i_1_1--; 43 break; 44 } 45 else 46 { 47 for(RG int i=1;i<=n;i++) 48 { 49 if(strcmp(a[i],all[i_1_1-1])==0) 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=0;i<len;i++) 61 { 62 c[i]=c[i]+32; 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=1; 72 for(RG int i=0;i<len;i++) 73 { 74 int len2=strlen(all[i+1]); 75 RG int tmp=0; 76 for(RG int j=0;j<len2;j++) 77 { 78 if(all[i+1][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,0,sizeof(sum)); 92 memset(f,0,sizeof(f)); 93 memset(tag,0,sizeof(tag)); 94 memset(cut,0,sizeof(cut)); 95 memset(ma,0,sizeof(ma)); 96 int cz=strlen(all[1]); 97 for(int i=2;i<=i_1_1;i++) 98 { 99 strcpy(all[1]+cz,all[i]); 100 cut[i-1]=cz; 101 cz=strlen(all[1]); 102 } 103 //连串 104 cut[i_1_1]=cz; 105 for(int i=0;i<cz;i++) 106 { 107 int j=all[1][i]-‘a‘; 108 ma[j][++sum[j]]=i; 109 } 110 //记字母位置 111 for(int k=0;k<len;k++) 112 { 113 int id=c[k]-‘a‘; 114 int ci=min(k+1,i_1_1); 115 int ti=1; 116 for(int i=0;i<cz;i++) 117 { 118 tag1[i]=tag[i]; 119 }//备份 120 for(int i=1;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-1) continue; 124 if(k==0) 125 { 126 tag1[ma[id][i]]=0;//标记 127 f[k][i]=1;//初始值 128 } 129 else 130 { 131 int t=c[k-1]-‘a‘; 132 for(int j=1;j<=sum[t];j++) 133 { 134 if(ma[t][j]<ma[id][i]&&ma[t][j]>=cut[ti-2]&&tag[ma[t][j]]==k-1) 135 { 136 f[k][i]+=f[k-1][j];//转移 137 tag1[ma[id][i]]=k;//标记×2 138 } 139 } 140 } 141 } 142 for(int i=0;i<cz;i++) 143 { 144 tag[i]=tag1[i];//备份 145 } 146 } 147 int ans=0; 148 for(int i=1;i<=sum[c[len-1]-‘a‘];i++) 149 { 150 ans+=f[len-1][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 0; 160 }
标签:答案 inux enter badge 长度 cut += cti 理解
原文地址:http://www.cnblogs.com/Renyi-Fan/p/7736540.html