题目描述

给定 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] 古城之谜的更多相关文章

  1. hdu4843(NOI2000) 古城之谜 (trie树+DP)

    Description 著名的考古学家石教授在云梦高原上发现了一处古代城市遗址.让教授欣喜的是在这个他称为冰峰城(Ice-Peak City)的城市中有12块巨大石碑,上面刻着用某种文字书写的资料,他 ...

  2. 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- ...

  3. dp方程

    1.        资源问题1 -----机器分配问题 F[I,j]:=max(f[i-1,k]+w[i,j-k]) 2.        资源问题2 ------01背包问题   F[I,j]:=ma ...

  4. pythonchallenge 解谜 Level 0

    解谜地址: http://www.pythonchallenge.com/pc/def/0.html 这题没什么难度,意思就是得到2的38次方的值,然后,替换 http://www.pythoncha ...

  5. pythonchallenge 解谜

    所有代码均使用python 3.5.1 版本 最近在学python,闲来无事觉得这个解谜还挺有意思. 解谜网址  http://www.pythonchallenge.com/ 接下来会写破解教程~

  6. 揭秘JavaScript中谜一样的this

      揭秘JavaScript中谜一样的this 在这篇文章里我想阐明JavaScript中的this,希望对你理解this的工作机制有一些帮助.作为JavaScript程序员学习this对于你的发展有 ...

  7. Activity的"singleTask"之谜

    官方文档称 以这种方式启动的Activity总是属于一个任务的根Activity.果真如此吗?本文将为你解开Activity的"singleTask"之谜. 任务(Task)是个什 ...

  8. Microsoft HoloLens 技术解谜(下)

    读者提问之“HoloLens 的深度传感器有没有可能是基于 TOF?” 先介绍下背景知识,市面上常见的有三种类型的深度传感器: 结构光,这个技术的代表产品是 Kinect 一代,它的传感器芯片用的是 ...

  9. 揭开Linux操作系统的Swap交换区之谜

    揭开Linux操作系统的Swap交换区之谜 Swap,即交换区,除了安装Linux的时候,有多少人关心过它呢?其实,Swap的调整对Linux服务器,特别是Web服务器的性能至关重要.通过调整Swap ...

随机推荐

  1. Python+Selenium自动化-清空输入框、输入内容、点击按钮

    Python+Selenium自动化-清空输入框.输入内容.点击按钮   1.输入内容 send_keys('valve'):输入内容valve #定位输入框 input_box = browser. ...

  2. Go语言的函数07---闭包练习(ATM存取款)

    package main import "fmt" /* @ATM(闭包练习) ·写一个Atm(函数),返回存款,取款两个内层函数 ·存款,取款两个函数,都以一个金额为参数,返回存 ...

  3. 书列荐书 |《至关重要的关系》 【美】里德&#183;霍夫曼

    本书的内容不算多,堪称精辟,有些东西甚至可以作为指导思想.括号内为书列君书评. 经典语录: 每个人都是企业家!(否则你无法最大化努力!) 创业和做人是相通的.我们要有计划,要执着,但是也要有弹性,懂得 ...

  4. .Net Core Api发布时报502.5 [The Application process failed to Start]问题的解决原因

       碰到这样的错误,在网上找了很久很久.我自己在部署的时候已经把Core 部署需要的环境包在服务器安装好了.还会报这个错,然后在网上找的安装了一个系统补丁包!安装之后还是不行.最后我把服务器重启了一 ...

  5. Gamma矫正技术

    Gamma矫正技术 一. gamma校正背景 在电视和图形监视器中,显像管发生的电子束及其生成的图像亮度并不是随显像管的输入电压线性变化,电子流与输入电压相比是按照指数曲线变化的,输入电压的指数要大于 ...

  6. GPU端到端目标检测YOLOV3全过程(上)

    GPU端到端目标检测YOLOV3全过程(上) Basic Parameters: Video: mp4, webM, avi Picture: jpg, png, gif, bmp Text: doc ...

  7. JDBC连接MySQL、Oracle和SQL server的配置

    什么是JDBC 我们可以将JDBC看作是一组用于用JAVA操作数据库的API,通过这个API接口,可以连接到数据库,并且使用结构化查询语言(SQL)完成对数据库的查找,更新等操作. JDBC连接的流程 ...

  8. android小技巧之点击两次退出活动

    通常在主活动中可以设置连击退出程序,下面通过代码来实现这一功能: @Override//按两次back键退出public boolean onKeyDown(int keyCode, KeyEvent ...

  9. 合宙Luat | 一文读懂LuaTask延时,看我如何从《射雕英雄传》角度分析。

    武侠小说中,主人公之所以能纵横江湖,常常离不开一样可遇不可求的绝世法宝--武功秘籍.如今勇于尝试的开发者,笃定地告诉后来者:选Luat二次开发,就如同拥有了物联网开发的武功秘籍. 本期让我们通过< ...

  10. Windows内核开发-Windows内部概述-1-

    Windows内部概述-1- 进程: 进程是一个程序的运行实例的控制和管理对象.一般的程序员所说进程运行,这样的说法是不对的,因为进程不能运行程序,进程只能管理该程序运行.线程才是真正的执行代码的东西 ...