1 条题解

  • 0
    @ 2025-8-24 22:14:06

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Illusory_dimes
    AFO on 2023/4/2

    搬运于2025-08-24 22:14:06,当前版本为作者最后更新于2021-07-08 13:02:38,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    题目描述

    给定 n 和 n 个信息,每个信息包含一个词性 a (只有三种:名,动,辅)和对应的词 mot ,形为“ a.mota.mot ”。(一次可能多词性)

    最后给一个长度不大于 5KB5KB 的冰峰文文章,将这篇冰峰文文章划分为最少的句子,在这个前提下,将文章划分为最少的单词时,求划分的句子数量和单词数量。

    划分标准: (别问我为什么盗图。。

    1n103    mot.len201\leq n\leq 10^3\ \ \ \ mot.len\leq 20

    solutionsolution

    首先要搞懂题目中的图是什么玩意(我真的看了好久都没看懂。。)

    所有语法简述下来就是:


    1.名词短语是许多个辅词加一个名词组成的。

    2.动词短语是许多个辅词加一个动词组成的。

    3.一个句子以名词短语开头,名词短语和动词短语交替出现而组成的。

    4.文章为多句话组成。


    所以对于任意词,有四种类型:


    1.名词。

    2.动词。

    3.辅名词的辅词。

    4.辅动词的辅词。


    状态应该很自然了。。(要什么设什么呗)

    f[j][i][0]f[j][i][0] 指前 ii 个字母,最后一个单词是名词,构成了 jj 个句子的最小单词数。

    f[j][i][1]f[j][i][1] 指前 ii 个字母,最后一个单词是动词,构成了 jj 个句子的最小单词数。

    f[j][i][2]f[j][i][2] 指前 ii 个字母,最后一个单词是辅词,后面要接动词,构成了 jj 个句子的最小单词数。

    f[j][i][3]f[j][i][3] 指前 ii 个字母,最后一个单词是辅词,后面要接名词,构成了 jj 个句子的最小单词数。

    状态转移方程就按照语法看能否转移就行

    $f[j][i][0] \Longrightarrow \min{(f[j][k][1/3],f[j-1][k][0/2])}$

    f[j][i][1]min(f[j][k][0/2])f[j][i][1] \Longrightarrow \min{(f[j][k][0/2])}

    f[j][i][2]min(f[j][k][0/2])f[j][i][2] \Longrightarrow \min{(f[j][k][0/2])}

    $f[j][i][3] \Longrightarrow \min{(f[j][k][1/3],f[j-1][k][0/1])}$

    实际上看式子的话, jj 那一维可以滚动起来。(虽然不滚掉好像问题不大,但省空间多好。。)

    最后答案就是按题目来,求一个最小的 ansans ,存在 f[ans][len][0/1]f[ans][len][0/1] ,如果都存在,取较小值。

    DPDP 这里就结束了,考虑如何实现。

    明显 DPDP 的复杂度不允许我们每次枚举所有单词再去比较。

    所以想到了用一个比较实用的东西 trietrie 可以把速度拉起来。

    基本上这题就搞定了,就是注意一定把数组开稍微大点(我因为忽略数组大小而傻乎乎地去调了半个小时程序了)

    codecode

    #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
    上传者