http://contest-hunter.org:83/contest/0x50%E3%80%8C%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%92%E3%80%8D%E4%BE%8B%E9%A2%98/5702%20Count%20The%20Repetitions

给两个串,第一个循环写$n1$次,求第二个最多可以循环写多少次使得其能与第一个循环串非连续匹配。$s \leqslant 100,n \leqslant 10^6$


这个博客貌似鸽了许久了。。

可以想到朴素算法,就是拿第二个串去暴力匹配第一个串,第一个串匹配完了后面再补,直到补到其制限次数。或者用序列自动机?循环串循环次数太多了2333。

可以看出,朴素算法中的一步一步匹配显然效率低下,考虑可不可以向后匹配一次就跳很多格?先处理出原串每个字符和模式串对应上之后向后再匹配1个字符跳的步数,然后由于循环节不大,用倍增优化即可。

$f[i][j][k]$表示文本串第$i$位和模式串第$j$位对应,然后向后匹配成功了$2^k$个字符后跳到文本串什么位置(取模),$g[i][j][k]$表示产生这种行为后文本串会被向后拓展多少次。

设$i'=f[i][j][k-1],j'=(j+2^{k-1}-1)mod$  $len_{s2}+1$

则转移为$f[i][j][k-1]=f[i'][j'][k-1]$,$g[i][j][k]=g[i][j][k-1]+g[i'][j'][k-1]$。

事实上设两种状态表示麻烦了,完全可以用f表示匹配若干2次幂字符后跳到文本串拓展后的哪一位,反正循环次数再多下标也只在int范围内,g数组就可以直接不求而利用f得知了。

最后开始匹配,枚举指数,拼凑最多可以跳多少次,除以$len_{s2}$出答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define dbg(x) cerr<<#x<<" = "<<x<<endl
#define _dbg(x,y) cerr<<#x<<" = "<<x<<" "<<#y<<" = "<<y<<endl
using namespace std;
typedef long long ll;
template<typename T>inline char MIN(T&A,T B){return A>B?A=B,:;}
template<typename T>inline char MAX(T&A,T B){return A<B?A=B,:;}
template<typename T>inline T _min(T A,T B){return A<B?A:B;}
template<typename T>inline T _max(T A,T B){return A>B?A:B;}
template<typename T>inline T read(T&x){
x=;int f=;char c;while(!isdigit(c=getchar()))if(c=='-')f=;
while(isdigit(c))x=x*+(c&),c=getchar();return f?x=-x:x;
}
const int N=+,LOG=;
vector<int> pos[];
int f[N][N][LOG],g[N][N][LOG],p[LOG];
char a[N],b[N];
int n1,n2,len1,len2,m,cnt,ans;
inline void calc_pow(){for(register int i=;i<=;++i)p[i]=(<<i)%len2;}
inline void Reset(){
for(register int i='a';i<='z';++i)pos[i].clear();
memset(f,,sizeof f),memset(g,,sizeof g);
}
inline char preprocess(){
int k,l;
for(register int i=;i<=len1;++i)pos[a[i]].push_back((int)i);
for(register int i=;i<=len2;++i)if(pos[b[i]].empty())return ;
for(register int j=;j<=len2;++j)
for(register int x=,i=pos[b[j]][];x<(int)pos[b[j]].size();++x,i=pos[b[j]][x]){
(k=j+)>len2?k=:k;
if(*--pos[b[k]].end()<=i)l=pos[b[k]][];else l=*upper_bound(pos[b[k]].begin(),pos[b[k]].end(),(int)i);
f[i][j][]=l,g[i][j][]=l<=i;
}
calc_pow();
for(register int k=;k<=m;++k)
for(register int j=;j<=len2;++j)
for(register int x=,i=pos[b[j]][];x<(int)pos[b[j]].size();++x,i=pos[b[j]][x])
if(f[i][j][]){
int i0=f[i][j][k-],j0=j+p[k-]-;j0>=len2&&(j0-=len2);++j0;
f[i][j][k]=f[i0][j0][k-],g[i][j][k]=g[i][j][k-]+g[i0][j0][k-];
}
return ;
} int main(){//freopen("test.in","r",stdin);freopen("test.out","w",stdout);
while(~scanf("%s%d",b+,&n2)){
scanf("%s%d",a+,&n1);
len1=strlen(a+),len2=strlen(b+);
m=__lg(n1*len1);Reset();
if(preprocess()){printf("0\n");continue;}
int x=pos[b[]][],y=;cnt=,ans=;
for(register int i=m;~i;--i){
if(cnt+g[x][y][i]<=n1){
cnt+=g[x][y][i],ans+=(<<i);
x=f[x][y][i];
y+=p[i]-;y>=len2&&(y-=len2);++y;
}
}
printf("%d\n",ans/len2/n2);
}
return ;
}

等一下。。我傻掉了。状态还可优化。将f改为$f[i][k]$表示从$i$开始匹配模式串(不管$i$自己有没有匹配上,简化了我原来强制要与$j$对应开始匹配的条件),至少匹配多少个字符才可以匹配出$2^k$个模式串。这样暴力预处理匹配单串之后,进行转移。空间和时间上都省了很多很多。→这种方法参考自lyd书。果然菜是原罪。QwQ

CH5702 Count The Repetitions[倍增dp]的更多相关文章

  1. 第七周 Leetcode 466. Count The Repetitions 倍增DP (HARD)

    Leetcode 466 直接给出DP方程 dp[i][k]=dp[i][k-1]+dp[(i+dp[i][k-1])%len1][k-1]; dp[i][k]表示从字符串s1的第i位开始匹配2^k个 ...

  2. CH5702 Count The Repetitions

    题意 5702 Count The Repetitions 0x50「动态规划」例题 描述 定义 conn(s,n) 为 n 个字符串 s 首尾相接形成的字符串,例如: conn("abc& ...

  3. Codeforces 1140G Double Tree 倍增 + dp

    刚开始, 我以为两个点肯定是通过树上最短路径过去的, 无非是在两棵树之间来回切换, 这个可以用倍增 + dp 去维护它. 但是后来又发现, 它可以不通过树上最短路径过去, 我们考虑这样一种情况, 起点 ...

  4. zoj 3649 lca与倍增dp

    参考:http://www.xuebuyuan.com/609502.html 先说题意: 给出一幅图,求最大生成树,并在这棵树上进行查询操作:给出两个结点编号x和y,求从x到y的路径上,由每个结点的 ...

  5. 洛谷 P1613 跑路 (倍增 + DP + 最短路)

    题目链接:P1613 跑路 题意 给定包含 \(n\) 个点和 \(m\) 条边的有向图,每条边的长度为 \(1\) 千米.每秒钟可以跑 \(2^k\) 千米,问从点 \(1\) 到点 \(n\) 最 ...

  6. 【BZOJ-1833】count数字计数 数位DP

    1833: [ZJOI2010]count 数字计数 Time Limit: 3 Sec  Memory Limit: 64 MBSubmit: 2494  Solved: 1101[Submit][ ...

  7. CF451D Count Good Substrings (DP)

    Codeforces Round #258 (Div. 2) Count Good Substrings D. Count Good Substrings time limit per test 2 ...

  8. hdu 3336 Count the string KMP+DP优化

    Count the string Problem Description It is well known that AekdyCoin is good at string problems as w ...

  9. uva 10712 - Count the Numbers(数位dp)

    题目链接:uva 10712 - Count the Numbers 题目大意:给出n,a.b.问说在a到b之间有多少个n. 解题思路:数位dp.dp[i][j][x][y]表示第i位为j的时候.x是 ...

随机推荐

  1. iOS 4.5.5版本 被拒绝!!!! "App Rejected : non-public APIs"

    今天上午收到邮件说是被拒绝了 原文是 这一版本 我就添加一个购买sku的方法, 并没有添加什么库 ,简简单单的一次升级给我出一私有方法拒绝!!!!! 在xcode8  iOS10 刚出来 ,苹果新规则 ...

  2. iOS 点击注释图标 弹出对应解释

    需求:如题目  接上一篇的开发内容 效果图: 这种情况存在tableView 的一个cell中. 要点 1,  弹出的对应解释 要在可视区域,并且小尖角 要指着 图片 2,  文本不能过高 有极大高度 ...

  3. c# 泛型(Generic)

    using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace 泛型 { ...

  4. 【leetcode刷提笔记】Search Insert Position

    Given a sorted array and a target value, return the index if the target is found. If not, return the ...

  5. 【Tech】单点登录系统CAS客户端demo

    服务器端配置请参考: http://www.cnblogs.com/sunshineatnoon/p/4064632.html 工具:myeclipse或者javaee-eclipse 1.启动jav ...

  6. 【Topcoder】SRM158 DIV2总结

    250分题:给定一个4位字符串initial和rotate这个字符串的方式,然后再给另一个字符串current,问current能否由initial通过rotate得到,需要几次rotate? 简单的 ...

  7. Android签名机制之---签名过程详解

    http://www.2cto.com/kf/201512/455388.html 一.前言 又是过了好长时间,没写文章的双手都有点难受了.今天是圣诞节,还是得上班.因为前几天有一个之前的同事,在申请 ...

  8. node中session存储与销毁,及session的生命周期

    1.首先在使用session之前需要先配置session的过期时间等,在入口文件app.js中 app.use(express.session({ cookie: { maxAge: config.g ...

  9. 单周期CPU设计

    终于有点时间了,恰好多周期的设计也已经完成,其实只想写写多周期的,无奈单周期补上才好,哈哈哈~ —————+—————黄金分割线—————+————— 首先要理解什么叫单周期CPU(与后面多周期CPU ...

  10. iOS_网络编程

    网络编程中有以下几种方式向服务器进行提交数据: IOS同步请求.异步请求.GET请求.POST请求 1.同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务器返回数据完成,才可 ...