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

Illusory_dimes
AFO on 2023/4/2搬运于
2025-08-24 22:14:06,当前版本为作者最后更新于2021-07-08 13:02:38,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
题目描述
给定 n 和 n 个信息,每个信息包含一个词性 a (只有三种:名,动,辅)和对应的词 mot ,形为“ ”。(一次可能多词性)
最后给一个长度不大于 的冰峰文文章,将这篇冰峰文文章划分为最少的句子,在这个前提下,将文章划分为最少的单词时,求划分的句子数量和单词数量。
划分标准:
(别问我为什么盗图。。首先要搞懂题目中的图是什么玩意(我真的看了好久都没看懂。。)
所有语法简述下来就是:
1.名词短语是许多个辅词加一个名词组成的。
2.动词短语是许多个辅词加一个动词组成的。
3.一个句子以名词短语开头,名词短语和动词短语交替出现而组成的。
4.文章为多句话组成。
所以对于任意词,有四种类型:
1.名词。
2.动词。
3.辅名词的辅词。
4.辅动词的辅词。
状态应该很自然了。。(要什么设什么呗)
指前 个字母,最后一个单词是名词,构成了 个句子的最小单词数。
指前 个字母,最后一个单词是动词,构成了 个句子的最小单词数。
指前 个字母,最后一个单词是辅词,后面要接动词,构成了 个句子的最小单词数。
指前 个字母,最后一个单词是辅词,后面要接名词,构成了 个句子的最小单词数。
状态转移方程就按照语法看能否转移就行
$f[j][i][0] \Longrightarrow \min{(f[j][k][1/3],f[j-1][k][0/2])}$
$f[j][i][3] \Longrightarrow \min{(f[j][k][1/3],f[j-1][k][0/1])}$
实际上看式子的话, 那一维可以滚动起来。(虽然不滚掉好像问题不大,但省空间多好。。)
最后答案就是按题目来,求一个最小的 ,存在 ,如果都存在,取较小值。
这里就结束了,考虑如何实现。
明显 的复杂度不允许我们每次枚举所有单词再去比较。
所以想到了用一个比较实用的东西 可以把速度拉起来。
基本上这题就搞定了,就是注意一定把数组开稍微大点(我因为忽略数组大小而傻乎乎地去调了半个小时程序了)
#include<bits/stdc++.h> #define reg register using namespace std; typedef long long ll; const int N=1e3+10,M=6e3+10,K=3e4+10; const int INF=0x3f3f3f3f; int n,m,mlth,f[2][M][4],tri[M][24],tot,op,ans1,ans2; char sw[M],sd[M]; struct trie{ int tr[26],opt,it; inline void clear(){ memset(tr,0,sizeof(tr)); it=-1;opt=0; } }trie[K]; inline int read(){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } inline void insert(char s[],int lth,int opt){ int id=0,val; for(int i=2;i<lth;++i){ val=s[i]-'a'; if(!trie[id].tr[val]){ trie[++tot].clear(); trie[tot].it=val; trie[id].tr[val]=tot; } id=trie[id].tr[val]; } trie[id].opt|=opt; } inline int find(int lt,int rt){ int id=0,val; for(int i=lt;i<=rt;++i){ val=sd[i]-'a'; if(!trie[id].tr[val])return 0; id=trie[id].tr[val]; } return trie[id].opt; } inline void mian(){ ans1=0;ans2=INF; trie[0].clear(); memset(tri,-1,sizeof(tri)); memset(f,INF,sizeof(f)); for(int i=1;i<=n;++i){ scanf("%s",sw);m=strlen(sw); mlth=max(m,mlth); if(sw[0]=='n')insert(sw,m,1); else if(sw[0]=='v')insert(sw,m,2); else if(sw[0]=='a')insert(sw,m,4); } scanf("%s",sd+1);m=strlen(sd+1)-1; f[0][0][0]=0; for(int lin=1;lin<=m;++lin){ int now=op^1,pre=op; for(int i=1;i<=m;++i){ memset(f[now][i],INF,sizeof(f[now][i])); int lim=max(i-mlth,0); for(int j=i-1;j>=lim;--j){ if(tri[j+1][i-j]==-1) tri[j+1][i-j]=find(j+1,i); int opti=tri[j+1][i-j],nowi,prei; if(opti&1){ nowi=min(f[now][j][1],f[now][j][3]); prei=min(f[pre][j][0],f[pre][j][2]); f[now][i][0]=min(f[now][i][0],nowi+1); f[now][i][0]=min(f[now][i][0],prei+1); }//不能有else if(opti&2){ nowi=min(f[now][j][0],f[now][j][2]); f[now][i][1]=min(f[now][i][1],nowi+1); }//不能有else if(opti&4){ nowi=min(f[now][j][0],f[now][j][2]); f[now][i][2]=min(f[now][i][2],nowi+1); nowi=min(f[now][j][1],f[now][j][3]); prei=min(f[pre][j][0],f[pre][j][1]); f[now][i][3]=min(f[now][i][3],nowi+1); f[now][i][3]=min(f[now][i][3],prei+1); }//不能有else } } ans2=min(f[now][m][0],f[now][m][1]); if(ans2!=INF){ans1=lin;break;} op^=1; } printf("%d\n%d\n",ans1,ans2); } int main(){ n=read(); mian(); return 0; }(话说为什么没题解呀。。
- 1
信息
- ID
- 4768
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 6
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者