题解 P1624 【单词缩写】
看大家都是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;
}