[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 ...
随机推荐
- 上传靶机实战之upload-labs解题
前言 我们知道对靶机的渗透可以提高自己对知识的掌握能力,这篇文章就对上传靶机upload-labs做一个全面的思路分析,一共21个关卡.让我们开始吧,之前也写过关于上传的专题,分别为浅谈文件上传漏洞( ...
- cachecloud生产环境搭建
步骤 1 机器管理 机器初始化Redis环境 添加机器 执行: cachecloud-init.sh脚本 2 cachecloud添加机器的时候需要添加一个用户cachecloud-open ad ...
- 将TVM集成到PyTorch
将TVM集成到PyTorch 随着TVM不断展示出对深度学习执行效率的改进,很明显PyTorch将从直接利用编译器堆栈中受益.PyTorch的主要宗旨是提供无缝且强大的集成,而这不会妨碍用户.PyTo ...
- FinFET与2nm晶圆工艺壁垒
FinFET与2nm晶圆工艺壁垒 谈到半导体工艺尺寸的时候,通常对于下面的一串数字耳熟能详:3um.2um.1.5um.1um.0.8um.0.5um.0.35um.0.25um.0.18um.0.1 ...
- Imec推出高性能芯片的低成本冷却解决方案
Imec推出高性能芯片的低成本冷却解决方案 Imec unveils low-cost cooling solution for high-performance chips 3D打印冷却器优于传统解 ...
- postgresql无序uuid性能测试
无序uuid对数据库的影响 由于最近在做超大表的性能测试,在该过程中发现了无序uuid做主键对表插入性能有一定影响.结合实际情况发现当表的数据量越大,对表插入性能的影响也就越大. 测试环境 Postg ...
- GD32F330 | ADC实例 基于DMA方式
GD32F330 | ADC实例 基于DMA方式 简单记录一下 ADC多通道转换 DMA搬运 的使用,以 GD32F330G8U6 为例: 一.ADC 基础知识 12位ADC是一种采用逐次逼近方式的模 ...
- Kubernetes 实战——发现应用(Service)
一.简介 服务:一种为一组功能相同的 Pod 提供单一不变的接入点的资源.服务 IP 和端口不会改变 对服务的连接会被路由到提供该服务的任意一个 Pod 上(负载均衡) 服务通过标签选择器判断哪些 P ...
- 【NX二次开发】Block UI 分割线
设置控件可见 this->separator0->GetProperties()->SetLogical("Show",true);
- 快速上手pandas(上)
pandas is a fast, powerful, flexible and easy to use open source data analysis and manipulation to ...