大学生程序设计邀请赛(华东师范大学)B. 分词 DP
B. 分词
有一句句子因为粘贴的时候出现了一点问题空格全部丢失了。现在给一本字典,每个词都对应这个词出现的频率(每十亿)。根据这个频率,我们可以根据下面的公式算出这个词带来的收益 P(word):
其中 frequency 就是上面所提到的频率。len 指的是单词的长度。
特别的,对于字典中没有出现过的词,P(word)=0。
请对句子进行适当的分割,使得分割得到的所有词收益之和最大。同一个词可以重复出现,收益算作多次。
Input
先给出一本词典,词典的第一行是词条数(词条数约为 40 000),下面每行分别是单词和对应出现频率,用空格隔开。单词中只会出现英文字母大小写,不会有多余的空格。每个单词只会出现一次。频率是一个正实数。
所有单词长度之和不超过 3⋅105,最长单词长度不超过 30。
接下来一行一个整数 T (T≤10),表示有 T 个查询。
下面 T 行,每行一个句子,句子长度不超过 5 000。句子中保证只含有英文字母大小写。注意单词匹配时,不区分大小写。
词典数据来源于 Wikipedia Project Gutenberg(可能需要代理),其中 1-10000 词汇。
查询数据来源于 IELTS Test。
Output
对于每组数据,输出两行。
第一行是一个实数,表示最大能达到的收益。输出和答案相差不超过 10−3 即可认为正确。
第二行输出一连串单词,单词和单词之间用空格隔开。满足:
- 把这些单词依次串联起来可以得到原句子;
- 所有单词的收益值相加得到第一行的实数。
Examples
5
ano 10
ther 30
another 10
an 300
other 20
1
another
112.826670
another
5
ano 10.0
ther 30.0
another 10.0
an 300.0
other 2000.0
1
another
212.837691
an other
Note
样例给出的词典与测试数据有所不同。
题解:
将字典建立AC自动机
设定dp[i]表示前i个字母划分可以得到的最大价值
那么它可以转移的地方就是 i - 当前的失配指针指向的trie树上的节点所表示的母串长度
直接暴力转移就行了。
同时用pre记录当前最优是从哪个决策点转过来的
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 5e5+, M = 1e3+, mod = 1e9+,inf = 2e5; double sum[N];
int len[N],nex[N][],cnt,head,tail,fail[N],q[N]; int ID(char ch) {
if(ch >= 'A' && ch <= 'Z') return ch - 'A';
else return ch - 'a';
}
void insert(char *s,double x) {
int now = , le = strlen(s);
for(int i = ; i < le; ++i) {
int index = ID(s[i]);
if(!nex[now][index])
nex[now][index] = ++cnt;
len[nex[now][index]] = len[now]+;
now = nex[now][index];
}
sum[now] = max(sum[now],x);
}
void build_fail() {
head = , tail = ;
for(int i = ; i < ; ++i) nex[][i] = ;
fail[] = ;
q[tail++] = ;
while(head != tail) {
int now = q[head++];
for(int i = ; i < ; ++i) {
int p = fail[now];
if(!nex[now][i]) {
nex[now][i] = nex[p][i];continue;
}
fail[nex[now][i]] = nex[p][i];
q[tail++] = nex[now][i];
}
}
}
double x,dp[N];
char s[N];
int Q,T,pre[N],v[N];
int main() {
scanf("%d",&T);
cnt = ;
for(int i = ; i <= T; ++i) {
scanf("%s%lf",s,&x);
insert(s,x);
}
build_fail();
scanf("%d",&Q);
while(Q--) {
scanf("%s",s+);
int n = strlen(s+);
dp[] = ;
int now = ;
memset(v,,sizeof(v));
memset(pre,,sizeof(pre));
for(int i = ; i <= n; ++i) {
int id = ID(s[i]);
now = nex[now][id];
int tmp = now;
while(tmp > ) {
if(sum[tmp] != ) {
int t = tmp;
double ns = dp[i - len[t]] + len[t]*len[t]*log(sum[t]);
if(ns - dp[i] > 0.00001) {
dp[i] = ns;
pre[i] = i - len[t];
}
tmp = fail[tmp];
}
else {
tmp = fail[tmp];
}
}
if(dp[i-] > dp[i]) {
pre[i] = i-;
dp[i] = dp[i-];
}
}
int tmp = n;
while(pre[tmp]) {
v[pre[tmp]] = ;
tmp = pre[tmp];
}
printf("%.10f\n",dp[n]);
for(int i = ; i <= n; ++i) {
printf("%c",s[i]);
if(v[i]) printf(" ");
}
printf("\n");
}
return ;
}
大学生程序设计邀请赛(华东师范大学)B. 分词 DP的更多相关文章
- “美登杯”上海市高校大学生程序设计邀请赛 (华东理工大学) E 小花梨的数组 线段树
题意 分析 预处理出每个数的最小素因子,首先可以知道\(minprime(x*minprime(x))=minprime(x)\),我们用线段树维护区间最大值\(mx[p]\),注意这里的最大值并不是 ...
- “美登杯”上海市高校大学生程序设计邀请赛 **D. 小花梨的取石子游戏**
"美登杯"上海市高校大学生程序设计邀请赛 (华东理工大学) D. 小花梨的取石子游戏 Description 小花梨有
- FZU - 2039 Pets (二分图匹配 2011年全国大学生程序设计邀请赛(福州))
Description Are you interested in pets? There is a very famous pets shop in the center of the ACM ci ...
- 2017中国大学生程序设计竞赛 - 女生专场B【DP】
B HDU - 6024 [题意]:n个教室,选一些教室建造糖果商店. 每个教室,有一个坐标xi和在这个教室建造糖果商店的花费ci. 对于每一个教室,如果这个教室建造糖果商店,花费就是ci,否则就是与 ...
- 美登杯”上海市高校大学生程序设计邀请赛 Problem E 、 小 花梨 的数组 (线段树)
Problem E E . 小 花梨 的数组 时间限制:1000ms 空间限制:512MB Description 小花梨得到了一个长度为
- 华东师范大学第十届ECNU Coder程序设计竞赛
华东师范大学第十届ECNU Coder程序设计竞赛 浮点数模运算 solution 转成整数然后取模. 时间复杂度:\(O(1)\) 数螃蟹 solution 找出公差出现次数最多的作为公差,然后找出 ...
- 2017中国大学生程序设计竞赛 - 女生专场(dp)
Building Shops Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) To ...
- 2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J Beautiful Numbers (数位DP)
2018 ACM 国际大学生程序设计竞赛上海大都会赛重现赛 J Beautiful Numbers (数位DP) 链接:https://ac.nowcoder.com/acm/contest/163/ ...
- HDU 6156 - Palindrome Function [ 数位DP ] | 2017 中国大学生程序设计竞赛 - 网络选拔赛
普通的数位DP计算回文串个数 /* HDU 6156 - Palindrome Function [ 数位DP ] | 2017 中国大学生程序设计竞赛 - 网络选拔赛 2-36进制下回文串个数 */ ...
随机推荐
- c++_最大公共子串
标题:最大公共子串 最大公共子串长度问题就是:求两个串的所有子串中能够匹配上的最大长度是多少. 比如:"abcdkkk" 和 "baabcdadabc",可以找 ...
- python 闭包&装饰器(一)
一.闭包 1.举例 def outer(): x = 10 def inner(): # 内部函数 print(x) # 外部函数的一个变量 return inner # 调用inner()函数的方法 ...
- JSP菜鸟之困
我一直想把java一套系统学好... 之前寒假学了android......feel good 大四又把jsp补习了一边.....85 但是苦于没有做过实例..... 暑假学PS之间想恶补一下jsp. ...
- NGINX模块(一)
[NGINX核心模块] 1.主模块 该模块包含一些Nginx的基本控制功能. 指令1:daemon 语法:daemon on | off 默认值:on daemon off; 说明:生产环境中不要使用 ...
- Linux 下Python2.7解决list打印中文字符问题
在写一个爬取智联招聘数据的爬虫中,将所需内容匹配到后打印出现了utf-8字符,并没有出现中文字符. 例如: >>>listnine = ['梨', '橘子', '苹果', '香蕉'] ...
- Android弹幕编程设计实现的解决方案(一)
Android弹幕编程设计实现的解决方案(一) 在现在的一些视频类网站.视频类直播网站,比如A站和B站,当视频在播放的时候,会在屏幕上出现一些滚动的字幕,这些字幕是UGC,通常是用户的评论,称之 ...
- HDU1021-Fibonacci Again,,找规律就好了~~~
Fibonacci Again Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) ...
- HDU 1358 next数组的推移
题目大意: 输入n,再输入一个长度为n的字符串,从第二位开始,计算它的前缀(包括他自己)中出现过的重复字符串的个数,如aabaabaabaab的第6位的前缀aabaab,aab连续出现了两次,所以输出 ...
- 实体类与实体DTO类之间的转换
实体类与实体DTO类之间的转换 实体类与实体DTO类之间的转换 1.通过使用第三方序列化反序列化工具Newtonsoft.Json 2.通过反射实现 3.通过表达式目录树加字典缓存实现 4. 通过表达 ...
- HDU 3001【状态压缩DP】
题意: 给n个点m条无向边. 要求每个点最多走两次,要访问所有的点给出要求路线中边的权值总和最小. 思路: 三进制状态压缩DP,0代表走了0次,1,2类推. 第一次弄三进制状态压缩DP,感觉重点是对数 ...