1 条题解
-
0
自动搬运
来自洛谷,原作者为

xgzc
苔花如米小,也学牡丹开。搬运于
2025-08-24 21:27:13,当前版本为作者最后更新于2017-09-23 19:59:41,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
看大家都是N^4或N³算法,N²算法还没有,
赶紧水一发基本思路:
把所有串连接起来,记录每个串的尾后位置,
设f[k][i]表示现在在处理缩写的第K个字符,在大字符串中第I个位置对前面字符的总贡献数,则f[k][i]=Σf[k-1][j],
其中j表示满足条件的前一个缩写字符。其中满足条件的定义为“无空缺单词,且是前一个字母”。则答案为Σf[最后一个字符][j],(1<=j<=n)。
为避免出现同一字母出现位置的不同,用一个数组进行标记即可。
###标记要一次打完才能更新!!!
#include<bits/stdc++.h> #define RG register using namespace std; int n; char a[110][200];//无效单词 char c1[200]; char c[200]; char all[200][200];//有效单词 int ma[26][200];//每个字母的有效位置 int tag[200]; int tag1[200];//两个标记 int cut[200];//单词的尾后位置 int sum[26];//出现的次数 int f[200][200];//dp数组 int main() { scanf("%d\n",&n); for(RG int i=1;i<=n;i++) { scanf("%s",a[i]); } scanf("%s",c1); while(1) { RG int i_1_1=1; strcpy(c,c1); if(strcmp(c,"LAST")==0) { scanf("%s",all[i_1_1++]); if(strcmp(all[i_1_1-1],"CASE")==0) break; } while(cin>>all[i_1_1++]) { RG int j=0; int len=strlen(all[i_1_1-1]); while(all[i_1_1-1][j]<'a'&&j<len) j++; if(j>=len) { strcpy(c1,all[i_1_1-1]); i_1_1--; break; } else { for(RG int i=1;i<=n;i++) { if(strcmp(a[i],all[i_1_1-1])==0) { i_1_1--; break; } } } } i_1_1--; printf("%s ",c); int len=strlen(c); for(RG int i=0;i<len;i++) { c[i]=c[i]+32; } //读入 if(len<i_1_1)//分类讨论 { puts("is not a valid abbreviation"); } else if(len==i_1_1) { int ans=1; for(RG int i=0;i<len;i++) { int len2=strlen(all[i+1]); RG int tmp=0; for(RG int j=0;j<len2;j++) { if(all[i+1][j]==c[i]) tmp++; } if(tmp) ans*=tmp; else { puts("is not a valid abbreviation"); break; } } printf("can be formed in %d ways\n",ans); } else //重点 { memset(sum,0,sizeof(sum)); memset(f,0,sizeof(f)); memset(tag,0,sizeof(tag)); memset(cut,0,sizeof(cut)); memset(ma,0,sizeof(ma)); int cz=strlen(all[1]); for(int i=2;i<=i_1_1;i++) { strcpy(all[1]+cz,all[i]); cut[i-1]=cz; cz=strlen(all[1]); } //连串 cut[i_1_1]=cz; for(int i=0;i<cz;i++) { int j=all[1][i]-'a'; ma[j][++sum[j]]=i; } //记字母位置 for(int k=0;k<len;k++) { int id=c[k]-'a'; int ci=min(k+1,i_1_1); int ti=1; for(int i=0;i<cz;i++) { tag1[i]=tag[i]; }//备份 for(int i=1;i<=sum[id]&&ma[id][i]<cut[ci];i++) { while(ma[id][i]>=cut[ti]) ti++; if(i_1_1-ti>len-k-1) continue; if(k==0) { tag1[ma[id][i]]=0;//标记 f[k][i]=1;//初始值 } else { int t=c[k-1]-'a'; for(int j=1;j<=sum[t];j++) { if(ma[t][j]<ma[id][i]&&ma[t][j]>=cut[ti-2]&&tag[ma[t][j]]==k-1) { f[k][i]+=f[k-1][j];//转移 tag1[ma[id][i]]=k;//标记×2 } } } } for(int i=0;i<cz;i++) { tag[i]=tag1[i];//备份 } } int ans=0; for(int i=1;i<=sum[c[len-1]-'a'];i++) { ans+=f[len-1][i];//求和 } if(ans) { printf("can be formed in %d ways\n",ans); } else puts("is not a valid abbreviation"); } } return 0; }
- 1
信息
- ID
- 617
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者