Problem

BZOJ

Solution

显然是一个同余系最短路问题,转移方案就是所有|S|-border的长度,有 \(O(n)\) 种,暴力跑dijkstra的复杂度为 \(O(n^2\log n)\) 。

有一个结论,一个字符串的border的长度可以被分为 \(\log |S|\) 个等差数列。

那么我们不如来考虑一个等差数列所造成的影响,设等差数列共有 \(m\) 项,初值为 \(x\) ,那么它可以被表示为 \(\{ kd+x,k\in[0,m)\}\)

\[f[i]=\min_{j=0}^{m-1}(f[(i-x-jd)\bmod n]+x+jd)
\]

如果我们能建立一个 \(\bmod x\) 的剩余系,那么接下来就相当于添加了一个 \(+d\) 的转移方案,但是这个转移有距离的限制。注意到能相互更新的状态会形成 \(\gcd(x,d)\) 个环,可以套路地拆下来并倍长,用单调队列即可解决距离的限制,时间复杂度为 \(O(x)\)。

那么就只需要解决两个剩余系相互转化的问题了。其实很简单,设旧表的模数为 \(p\),新表的模数为 \(q\),只需要把旧表中每一列的最小能表达的值作为初始值放入新表中,然后只需要把转移方案 \(+p\) 加入表中,更新一次即可,这样的复杂度是 \(O(q)\) 的。

总的时间复杂度为 \(O(\sum n\log n)\)

注意把用来存border的数组,把a[len+1]的值清为0,这样才不会导致判的等差数列。

Code

#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int maxn=500010;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
x=0;int f=0;char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') f=1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
if(f) x=-x;
}
int z,n,k,tot,top,now,nxt[maxn],a[maxn],stk[maxn<<1];
int l,r,q[maxn<<1];
ll w,ans,f[maxn],g[maxn];
char s[maxn];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void trans(int x)
{
int D=gcd(x,now);
memset(g,0x3f,x<<3);
for(int i=0;i<now;i++) getmin(g[f[i]%x],f[i]);
for(int i=0;i<D;i++)
{
top=0;
for(int j=i;top==0||j!=i;j=(j+now)%x) stk[++top]=j;
for(int j=1;j<=top;j++) stk[j+top]=stk[j];
top<<=1;
for(int j=2;j<=top;j++)
getmin(g[stk[j]],g[stk[j-1]]+now);
}
memmove(f,g,x<<3);
now=x;
}
void solve(int x,int d,int m)
{
trans(x);
if(d<0) return ;
int D=gcd(x,d);
for(int i=0;i<D;i++)
{
top=0;l=1;r=0;
for(int j=i;top==0||j!=i;j=(j+d)%x) stk[++top]=j;
for(int j=1;j<=top;j++) stk[j+top]=stk[j];
top<<=1;
for(int j=1;j<=top;j++)
{
while(l<=r&&j-q[l]>=m) ++l;
if(l<=r) getmin(f[stk[j]],f[stk[q[l]]]+(j-q[l])*d+x);
while(l<=r&&f[stk[q[r]]]+(j-q[r])*d>f[stk[j]]) --r;
q[++r]=j;
}
}
}
int main()
{
read(z);
while(z--)
{
read(n);read(w);scanf("%s",s);
ans=tot=k=0;memset(f,0x3f,n<<3);
for(int i=1;i<n;i++)
{
while(k&&s[k]!=s[i]) k=nxt[k];
if(s[k]==s[i]) nxt[i+1]=++k;
else nxt[i+1]=0;
}
for(int i=nxt[n];i;i=nxt[i]) a[++tot]=n-i;
now=n;f[0]=n;a[tot+1]=0;
for(int i=1,j=1;i<=tot;i=j)
{
while(a[j+1]-a[j]==a[i+1]-a[i]) j++;
solve(a[i],a[i+1]-a[i],j-i);
}
for(int i=0;i<now;i++) if(f[i]<=w) ans+=(w-f[i])/now+1;
printf("%lld\n",ans);
}
return 0;
}

BZOJ4406 WC2016 论战捆竹竿的更多相关文章

  1. bzoj4406: [Wc2016]论战捆竹竿&&uoj#172. 【WC2016】论战捆竹竿

    第二次在bzoj跑进前十竟然是因为在UOJ卡常致死 首先这个题其实就是一个无限背包 一般做法是同余最短路,就是bzoj2118: 墨墨的等式可以拿到30分的好成绩 背包是个卷积就分治FFT优化那么下面 ...

  2. luogu P4156 [WC2016]论战捆竹竿

    传送门 官方题解(证明都在这) 神仙题鸭qwq 转化模型,发现这题本质就是一个集合,每次可以加上集合里的数,问可以拼出多少不同的数 首先暴力需要膜意义下的最短路,例题戳这 然后这个暴力可以优化成N^2 ...

  3. Luogu4156 WC2016 论战捆竹竿 KMP、同余类最短路、背包、单调队列

    传送门 豪华升级版同余类最短路-- 官方题解 主要写几个小trick: \(1.O(nm)\)实现同余类最短路: 设某一条边长度为\(x\),那么我们选择一个点,在同余类上不断跳\(x\),可以形成一 ...

  4. 「WC2016」论战捆竹竿

    「WC2016」论战捆竹竿 前置知识 参考资料:<论战捆竹竿解题报告-王鉴浩>,<字符串算法选讲-金策>. Border&Period 若前缀 \(pre(s,x)​\ ...

  5. UOJ#172. 【WC2016】论战捆竹竿 字符串 KMP 动态规划 单调队列 背包

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ172.html 题解 首先,这个问题显然是个背包问题. 然后,可以证明:一个字符串的 border 长度可 ...

  6. UOJ#172. 【WC2016】论战捆竹竿

    传送门 首先这个题目显然就是先求出所有的 \(border\),问题转化成一个可行性背包的问题 一个方法就是同余类最短路,裸跑 \(30\) 分,加优化 \(50\) 分 首先有个性质 \(borde ...

  7. 【WC2016】论战捆竹竿

    已经快三周了啊--终于把挖的坑填了-- 首先显然是把除了自身的所有border拿出来,即做 \(\left\{ n - b_1, n - b_2, \dots, n - b_k, n \right\} ...

  8. 【LuoguP4156】论战捆竹竿

    题目链接 题意简述 你有一个长度为 n 的字符串 , 将它复制任意次 , 复制出的串的前缀可以与之前的串的后缀重叠在一起 , 问最后总共可能的长度数目 , 长度不能超过 \(w\) 多组数据. \(n ...

  9. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

随机推荐

  1. Sping Aop日志实现(六)--日志查询功能

    最终效果: 日志查询流程分析: Controller代码: Mapper:

  2. 题解-APIO2019路灯

    problem \(\mathtt {loj-3146}\) 题意概要:一条直线上有 \(n+1\) 个点和 \(n\) 条道路,每条道路连通相邻两个点.在 \(q\) 个时刻内,每个时刻有如下两种操 ...

  3. Security Access Control Strategy && Method And Technology Research - 安全访问控制策略及其方法技术研究

    1. 访问控制基本概念 访问控制是网络安全防范和客户端安全防御的重要基础策略,它的主要任务是保证资源不被非法使用.保证网络/客户端安全最重要的核心策略之一. 访问控制包括 入网访问控制 网络权限控制 ...

  4. 使用File类、StreamRead和StreamWrite读写数据、以及Path类操作文件路径和Directory

    1.File类的概念: File类,是一个静态类,主要是来提供一些函数库用的.静态实用类,提供了很多静态的方法,支持对文件的基本操作,包括创建,拷贝,移动,删除和 打开一个文件. File类方法的参量 ...

  5. Datatable批量导入到表

    封装批量提交数据到表,用于数据同步作业 private string GetSelectFieldNames(DataTable dataTable, string tableName = " ...

  6. kubernets 证书过期的问题

    .问题起源 kubeadm 是 kubernetes 提供的一个初始化集群的工具,使用起来非常方便.但是它创建的apiserver.controller-manager等证书默认只有一年的有效期,同时 ...

  7. pymysql操作mysql数据库

    1.建库 import pymysql # 建库 try: conn=pymysql.connect( host='127.0.0.1', port=3306, user='root', passwd ...

  8. Vue 案例 列表动画实例

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. MongoDB简介,安装,增删改查

    MongoDB到底是什么鬼? 最近有太多的同学向我提起MongoDB,想要学习MongoDB,还不知道MongoDB到底是什么鬼,或者说,知道是数据库,知道是文件型数据库,但是不知道怎么来用 那么好, ...

  10. 现在记录几款好用的vscode的插件

    vscode 插件 Rainbow Brackets编码过程中,尤其在我们使用js进行函数式编程时,代码里会有很多的花括号,想要保证它们对称十分困难,所以就出现了上面小粉同学的尴尬局面,相信很多人都遇 ...