[NOI2000] 古城之谜
题目描述
给定 n 和 n 个信息,每个信息包含一个词性 a (只有三种:名,动,辅)和对应的词 mot ,形为“ \(a.mot\) ”。(一次可能多词性)
最后给一个长度不大于 \(5KB\) 的冰峰文文章,将这篇冰峰文文章划分为最少的句子,在这个前提下,将文章划分为最少的单词时,求划分的句子数量和单词数量。
划分标准:

(别问我为什么盗图。。
\(1\leq n\leq 10^3\ \ \ \ mot.len\leq 20\)
\(solution\)
首先要搞懂题目中的图是什么玩意(我真的看了好久都没看懂。。)
所有语法简述下来就是:
1.名词短语是许多个辅词加一个名词组成的。
2.动词短语是许多个辅词加一个动词组成的。
3.一个句子以名词短语开头,名词短语和动词短语交替出现而组成的。
4.文章为多句话组成。
所以对于任意词,有四种类型:
1.名词。
2.动词。
3.辅名词的辅词。
4.辅动词的辅词。
状态应该很自然了。。(要什么设什么呗)
\(f[j][i][0]\) 指前 \(i\) 个字母,最后一个单词是名词,构成了 \(j\) 个句子的最小单词数。
\(f[j][i][1]\) 指前 \(i\) 个字母,最后一个单词是动词,构成了 \(j\) 个句子的最小单词数。
\(f[j][i][2]\) 指前 \(i\) 个字母,最后一个单词是辅词,后面要接动词,构成了 \(j\) 个句子的最小单词数。
\(f[j][i][3]\) 指前 \(i\) 个字母,最后一个单词是辅词,后面要接名词,构成了 \(j\) 个句子的最小单词数。
状态转移方程就按照语法看能否转移就行
\(f[j][i][0] \Longrightarrow \min{(f[j][k][1/3],f[j-1][k][0/2])}\)
\(f[j][i][1] \Longrightarrow \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])}\)
实际上看式子的话, \(j\) 那一维可以滚动起来。(虽然不滚掉好像问题不大,但省空间多好。。)
最后答案就是按题目来,求一个最小的 \(ans\) ,存在 \(f[ans][len][0/1]\) ,如果都存在,取较小值。
\(DP\) 这里就结束了,考虑如何实现。
明显 \(DP\) 的复杂度不允许我们每次枚举所有单词再去比较。
所以想到了用一个比较实用的东西 \(trie\) 可以把速度拉起来。
基本上这题就搞定了,就是注意一定把数组开稍微大点(我因为忽略数组大小而傻乎乎地去调了半个小时程序了)
\(code\)
#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;
}
[NOI2000] 古城之谜的更多相关文章
- hdu4843(NOI2000) 古城之谜 (trie树+DP)
Description 著名的考古学家石教授在云梦高原上发现了一处古代城市遗址.让教授欣喜的是在这个他称为冰峰城(Ice-Peak City)的城市中有12块巨大石碑,上面刻着用某种文字书写的资料,他 ...
- dp式子100个……
1. 资源问题1-----机器分配问题F[I,j]:=max(f[i-1,k]+w[i,j-k]) 2. 资源问题2------01背包问题F[I,j]:=max(f[i- ...
- dp方程
1. 资源问题1 -----机器分配问题 F[I,j]:=max(f[i-1,k]+w[i,j-k]) 2. 资源问题2 ------01背包问题 F[I,j]:=ma ...
- pythonchallenge 解谜 Level 0
解谜地址: http://www.pythonchallenge.com/pc/def/0.html 这题没什么难度,意思就是得到2的38次方的值,然后,替换 http://www.pythoncha ...
- pythonchallenge 解谜
所有代码均使用python 3.5.1 版本 最近在学python,闲来无事觉得这个解谜还挺有意思. 解谜网址 http://www.pythonchallenge.com/ 接下来会写破解教程~
- 揭秘JavaScript中谜一样的this
揭秘JavaScript中谜一样的this 在这篇文章里我想阐明JavaScript中的this,希望对你理解this的工作机制有一些帮助.作为JavaScript程序员学习this对于你的发展有 ...
- Activity的"singleTask"之谜
官方文档称 以这种方式启动的Activity总是属于一个任务的根Activity.果真如此吗?本文将为你解开Activity的"singleTask"之谜. 任务(Task)是个什 ...
- Microsoft HoloLens 技术解谜(下)
读者提问之“HoloLens 的深度传感器有没有可能是基于 TOF?” 先介绍下背景知识,市面上常见的有三种类型的深度传感器: 结构光,这个技术的代表产品是 Kinect 一代,它的传感器芯片用的是 ...
- 揭开Linux操作系统的Swap交换区之谜
揭开Linux操作系统的Swap交换区之谜 Swap,即交换区,除了安装Linux的时候,有多少人关心过它呢?其实,Swap的调整对Linux服务器,特别是Web服务器的性能至关重要.通过调整Swap ...
随机推荐
- 解决使用go get 下载模块下载超时的问题
解决使用go get 下载模块下载超时的问题 解决使用go get 下载模块下载超时的问题 使用go env可以看到,默认的GOPROXY的值是https://proxy.golang.org, ...
- GO语言常用标准库04---flag读取命令行参数
package main import ( "flag" "fmt" "math" "os" ) /* go build ...
- cuGraph-GPU图形分析
cuGraph-GPU图形分析 所述RAPIDS cuGraph库是GPU的集合加速图形算法,在GPU DataFrames中发现过程数据.cuGraph的愿景是使图分析无处不在,以至于用户只是根据分 ...
- 编译器架构Compiler Architecture(下)
编译器架构Compiler Architecture(下) Combining Scanning and Parsing 实际上没有必要将扫描(词法分析/标记化)与解析(语法分析/树生成)分开.基于P ...
- MySQL笔记01(黑马)
一.数据库基本介绍 目标:了解数据库的功能和常见数据库分类.数据库产品 数据库基本知识 数据库分类 SQL简介 MySQL访问 1.数据库基本知识 目标:了解数据库的概念和数据库的作用 概念 数据库: ...
- hashmap专题
hashmap重要变量 源码中定义了很多常量,有几个是特别重要的. DEFAULT_INITIAL_CAPACITY: Table数组的初始化长度: 1 << 4,即 2^4=16(这里可 ...
- C++ QT安装教程2021
第一步 去官网下载 https://download.qt.io/archive/qt/ 第二步 next 然后 我是注册的账号 注意密码的格式,要求至少7位,包含大小写字母和数字 第三步 点击下一步 ...
- pytest skip的使用
skip跳过用例(无条件跳过,不运行用例) 使用方法: 1.使用跳过装饰器 class TestClass(): @pytest.mark.skip(reason='no way of current ...
- Centos8.3、mysql8.0主从复制实战记录
引言 最近又上线了一个项目,感觉自己这段时间收获不少就想把自己做这个项目用的技术总结梳理一下.这个项目是我自己发起,领导们不是特别重视所以得到资源有限,资源有限的情况我只能选择手动搭建数据库环境,资源 ...
- 【题解】codeforces 467C George and Job dp
题目描述 新款手机 iTone6 近期上市,George 很想买一只.不幸地,George 没有足够的钱,所以 George 打算当一名程序猿去打工.现在George遇到了一个问题. 给出一组有 n ...