HDU 5763 Another Meaning dp+字符串hash || DP+KMP
题意:给定一个句子str,和一个单词sub,这个单词sub可以翻译成两种不同的意思,问这个句子一共能翻译成多少种不能的意思
例如:str:hehehe sub:hehe 那么,有**he、he**、和hehehe三种不同的意思,
考虑一下aaadaaa这种情况?sub:aa 前面的aaa有三种,后面的aaa有三种,所以一共应该是有9种情况。
可以考虑成3*3=9
如果你考虑分块去相乘的话,那么恭喜你,你GG了。因为这样写非常复杂,而且非常难判断。
可以考虑下dp,因为注意到,它每个单词只有两种状态,要么转换成其他意思,要么就保留原意。
记dp[i]为匹配到str的第i个字符,所拥有的方案数,那么,如果不转换意思,dp[i] = dp[i-1]
就是方案数是没增加的,还是原来拥有的总数。
那么考虑转义。需要str[i-lensub+1...i]这段字符和sub一模一样,你才能转义把?
这里可以用字符串hash的方法O(1)判断
那么dp[i] += dp[i-lenstub];
就是在屏蔽str[i-lensub+1...i]这段字符的情况下,拥有的方案数,+我的转义,就是一种全新的方案,所以匹配到这个字符的时候,方案数要加上屏蔽这段字符前拥有的方案数
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
typedef unsigned long long int ULL;
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = +;
char str[maxn];
char sub[maxn];
LL dp[maxn];
const int MOD = 1e9+;
ULL sumhash[maxn];
ULL powseed[maxn];
const int seed = ;
ULL calc (int begin,int end)
{
return sumhash[end] - powseed[end-begin+]*sumhash[begin-];
}
int f;
void work ()
{
scanf("%s%s",str+,sub+);
int lenstr = strlen(str+);
int lensub = strlen(sub+);
ULL sub_hash = ; for (int i=;i<=lensub;++i) sub_hash = sub_hash*seed + sub[i];
for (int i=;i<=lenstr;++i) sumhash[i] = sumhash[i-]*seed + str[i]; for (int i=;i<=lensub;++i) dp[i]=;
// printf ("%I64u\n",sub_hash);
// printf ("%I64u\n",sumhash[4]);
for (int i=lensub;i<=lenstr;++i)
{
dp[i] = dp[i-];
//printf ("%d %d %I64u\n",i-lensub+1,i,calc(i-lensub+1,i));
if (calc(i-lensub+,i) == sub_hash)
{
dp[i] += dp[i-lensub];
}
dp[i] %= MOD;
}
printf ("Case #%d: %I64d\n",++f,dp[lenstr]);
return ;
} int main()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
powseed[]=;
for (int i=;i<=maxn-;++i) powseed[i] = powseed[i-]*seed;
int t;
scanf("%d",&t);
while (t--) work();
return ;
}
这题也可以用kmp做的
就是kmp匹配一次后,用个isok数组保存str的第i位能否匹配成功就可以了
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;
typedef unsigned long long int ULL;
#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int maxn = +;
char str[maxn];
char sub[maxn];
LL dp[maxn];
bool isok[maxn];
const int MOD = 1e9+;
int f;
void get_next (char sub[],int nextliu[],int len)
{
int i=,j=;
nextliu[]=;//记得初始值不能忘记
//next[len+1]这个也有值了 后面的++i和++j先加后赋值
while (i<=len)
{
//sub[i]的含义,后缀的单个字符
//sub[j]的含义,前缀的单个字符
if (j== || sub[i]==sub[j])//考虑的是上一个的
{
nextliu[++i]=++j; //用是上一个的比较,值的当前的值
}
else j=nextliu[j];
}
return ;
}
int nextliu[maxn];
int kmp (char str[],char sub[],int pos)
{
int len1=strlen(str+);
int len2=strlen(sub+);
//int next[maxn]={0};//maxn为最大长度
get_next(sub,nextliu,len2);//得到next[]数组
int i=pos;//从哪里出发
int j=;
int ans=;
while (i<=len1)
{
if (j== || str[i]==sub[j])
{
i++;j++;
}
else j=nextliu[j];
if (j==len2+)//有一个了
{
isok[i-]=; //标记这个位置是OK的
ans++;
j=nextliu[j];//回溯匹配
//i值不用回溯的
}
}
return ans;
} void work ()
{
scanf("%s%s",str+,sub+);
int lenstr = strlen(str+);
int lensub = strlen(sub+);
memset(isok,,sizeof isok);
kmp(str,sub,);
for (int i=;i<=lensub;++i) dp[i]=;
// for (int i=1;i<=lenstr;++i)
// {
// printf ("%d ",isok[i]);
// }
// printf ("\n");
for (int i=lensub;i<=lenstr;++i)
{
dp[i]=dp[i-];
if (isok[i]) dp[i] += dp[i-lensub];
dp[i] %= MOD;
}
printf ("Case #%d: %I64d\n",++f,dp[lenstr]);
return ;
} int main()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf("%d",&t);
while (t--) work();
return ;
}
Count the string
统计所有前缀在本串中出现的次数和
kmp + dp
利用next数组。
给定一个长为lenstr(<=20W)的字符串,要求找出所有前缀在本串中出现的次数,在这里前缀有,"a","ab","aba","abab" ans=2+2+1+1=6。思路:利用next[]的意义,最大的前缀和后缀匹配,那么,设dp[i]表示以第i个字符串结尾的所有子串(记住一定要是第i个字符串结尾,不要以为dp[n]就是答案,子串还有很多),和前i个字符的前缀(前缀一定是:s[1],s[1]s[2],s[1]s[2]s[3],这样的,不能是s[2]s[3]这样的。)所匹配的数目。那么,既然前缀和后缀相同,abab*****abab,那么,我的dp[i]=dp[next[i+1]-1]+1。(+1)是为了加上自己那个串,出现了一次。
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
#define inf (1<<28)
typedef long long int LL; #include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
const int MOD = ;
const int maxn = +;
char str[maxn];
void get_next (char sub[],int nextliu[],int len)
{
nextliu[]=;
int i=,j=;
while (i<=len)
{
if (j== || sub[i]==sub[j])
{
nextliu[++i]=++j;
}
else j=nextliu[j];
}
return ;
}
int nextliu[maxn];
int dp[maxn]={};
void work ()
{
int lenstr;
scanf ("%d",&lenstr);
scanf ("%s",str+);
get_next(str,nextliu,lenstr);
/*
for (int i=1;i<=lenstr;i++)
{
printf ("%d ",next[i]);
}
printf ("\n");*/ int ans=;
for (int i=;i<=lenstr;i++)
{
dp[i]=dp[nextliu[i+]-]+;
ans += dp[i];
ans %= MOD;
}
printf ("%d\n",ans);
return ;
} int main ()
{
#ifdef local
freopen("data.txt","r",stdin);
#endif
int t;
scanf ("%d",&t);
while (t--)
{
work ();
}
return ;
}
HDU 5763 Another Meaning dp+字符串hash || DP+KMP的更多相关文章
- HDU 5763 Another Meaning
HDU 5763 Another Meaning 题意:一个字串有可能在模式串出现多次,问有多少种可能出现的情况.关键是有重合的字串是不能同时计入的. 思路:先用kmp求出所有字串的位置.然后,dp. ...
- HDU 5763 Another Meaning KMP+DP
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5763 Another Meaning Time Limit: 2000/1000 MS (Java/ ...
- CodeForces7D 字符串hash + dp
https://cn.vjudge.net/problem/20907/origin 长度是 n 的字符串 s,如果它自身是回文数,且它的长度为 的前缀和后缀是 (k - )-回文数,则它被称作 k- ...
- [CQOI2014][bzoj3507] 通配符匹配 [字符串hash+dp]
题面 传送门 思路 0x01 KMP 一个非常显然而优秀的想法:把模板串按照'*'分段,然后对于每一段求$next$,'?'就当成可以对于任意字符匹配就行了 对于每个文本串,从前往后找第一个可以匹配的 ...
- HDU 1880 魔咒词典 (字符串hash)
<题目链接> 题目大意: 就是每个字符串有一个配套的对应字符串,询问的时候,无论输出其中的哪一个字符串,输出另一个,如果不存在这个字符串,直接输出"what?". 解题 ...
- HDU 5763 Another Meaning (kmp + dp)
Another Meaning 题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5763 Description As is known to all, ...
- HDU 5763 Another Meaning(DP+KMP)
http://acm.hdu.edu.cn/showproblem.php?pid=5763 题意: 给出一个字符串和一个模式串,模式串有两种意思,问这句话有几种意思. 思路:因为肯定要去字符串去找模 ...
- TTTTTTTTTTTTTT hdu 5763 Another Meaning 哈希+dp
Another Meaning Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)T ...
- HDU 5763 Another Meaning (KMP/哈希+DP)
题目大意:给你两个串,一长一短,如果长串中某个子串和短串完全相同,则这个子串可以被替换成"#",求长串所有的表达形式....... 比如"hehehehe"和& ...
随机推荐
- 如何调整chm文字字体大小
chm文档是使用用层叠样式表来控制字符大小的,通过IE的改变“文字大小”是没效果的,那我们是不是就没有办法改变它的大小了呢?显然不是的. 工具/原料 chm文件 方法/步骤 首先打开chm ...
- Android精品源码分享第四波袭来,免费下载!
今天又汇总了几个优质的源码分享出来给大家!希望可以帮到需要的朋友~1.Android实现-带动画的饼图控件 分享的是Android技术相关的源码内容,希望对大家的Android学习有帮助.带动画的饼图 ...
- Java之网络编程UDP和TCP
注*部分转来的 第1章 网络通信协议 通过计算机网络可以使多台计算机实现连接,位于同一个网络中的计算机在进行连接和通信时需要遵守一定的规则,这就好比在道路中行驶的汽车一定要遵守交通规则一样.在计算机网 ...
- C++二叉树结构的建立和操作
二叉树是数据结构中的树的一种特殊情况,有关二叉树的相关概念,这里不再赘述,如果不了解二叉树相关概念,建议先学习数据结构中的二叉树的知识点. 准备数据 定义二叉树结构操作中需要用到的变量及数据等. #d ...
- Entity Framework Code-First(10.1):EntityTypeConfiguration
EntityTypeConfiguration Class in Code-First: Before we start to configure using Fluent API, let's se ...
- C#和Python 图片和base64的互转
C#实例代码: /// <summary> /// 图片转base64 /// </summary> /// <param name="bmp"> ...
- Gson应用:从json格式简单字符串中获取value
import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStreamReader; i ...
- 程序员笔记|常见的Spring异常分析及处理
一.前言 相信我们每个人在SpringMVC开发中,都遇到这样的问题:当我们的代码正常运行时,返回的数据是我们预期格式,比如json或xml形式,但是一旦出现了异常(比如:NPE或者数组越界等等),返 ...
- wxpython实现文件拖拽
我想让wx.grid里面的单元格能够支持文件拖拽,实现起来挺简单的,共分3步: 1.创建一个wx.FileDropTarget子类的对象,并把要支持拖拽的控件传给它的构造函数,此处是grid 2.调用 ...
- [Xcode 实际操作]四、常用控件-(17)为MKMapView地图上显示提示框
目录:[Swift]Xcode实际操作 本文将演示当点击地图上的标注圆点时,弹出信息窗口. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit ...