upd:19.12.19

重新写了这道题,并且修正了原来题解描述中一些奇怪的东西

然后重新发出来假装根了脖


luogu

uoj

官方题解(证明都在这)

神仙题鸭qwq

转化模型,如果原串存在一个长度为\(i(i<n)\)的\(\mathrm{border}\),那么每次可以往后面加\(n-i\)的长度,所以这题本质是有一个集合(这题里\(n\)也属于这个集合),每次可以往后面加上集合内的一个数,问在给定范围内能凑出来的数的数量

这显然是同余类最短路,枚举集合中一个数\(a_1\)作为模数,然后求出\(di_i\)表示模\(a_1\)意义下为\(i\)的数中能凑出来的最小数

这个暴力是可以优化成\(O(n|S|)\)的.具体操作是枚举每个数\(a_i\),然后只用这个数往后跳,这样在膜\(m\)意义下可以形成\(gcd(a_i,m)\)个环.对每个环找到\(di\)最小的点,从这个点开始依次遍历整个环,更新后一个位置

有个结论是集合中的数(也就是所有合法\(\mathrm{border}\)长度)可以分成\(logn\)个等差数列,所以可以枚举每个等差数列贡献答案.具体的设某个等差序列首项为\(b\),公差为\(d\),项数为\(l\),然后当前同余最短路模数为\(a\),先把模\(a\)意义的最短路转成模\(b\)意义的最短路.具体操作是用模\(a\)意义下的所有\(di\)更新模\(b\)意义下的一些\(di\),然后从每个环的最小\(di\)处以\(a\)为跳跃距离更新其他的点.对于公差的贡献,相当于每个位置以\(d\)作为跳跃距离往后跳最多\(l-1\)次,然后转移跳到的位置,转移大概为\(\forall k \in [1,l-1],di_{(x+dk)\% b}=\min(di_{(x+dk)\% b},di_x+b+dk)\),这个东西用个单调队列优化转移即可.

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long using namespace std;
const int N=5e5+10;
LL rd()
{
LL x=0,w=1;char ch=0;
while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int ad(int x,int y,int z){x+=y,x-=x>=z?z:0;return x;} //加上这个就能过extest了~~然后垫底~~
int gcd(int a,int b){return b?gcd(b,a%b):a;}
uLL ha[N],hb[N],b1=233,hha[N],hhb[N],b2=677,mod=993244853;
int n,a[N],m,hd,tl;
LL di[N],d2[N],ln,q[N][2];
char cc[N]; int main()
{
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
int T=rd();
while(T--)
{
n=rd(),ln=rd()-n;
scanf("%s",cc+1);
for(int i=1;i<=n;++i)
ha[i]=ha[i-1]*b1+cc[i],hha[i]=(1ll*hha[i-1]*b2%mod+cc[i])%mod;
uLL p1=1,p2=1;
hb[n+1]=hhb[n+1]=0;
for(int i=n;i;--i)
{
hb[i]=hb[i+1]+cc[i]*p1,hhb[i]=(hhb[i+1]+1ll*cc[i]*(int)p2%mod)%mod;
p1*=b1,p2=p2*b2%mod;
}
m=0;
for(int i=n-1;i;--i)
if(ha[i]==hb[n-i+1]&&hha[i]==hhb[n-i+1]) a[++m]=n-i;
int sz=n;
memset(di,0x3f3f3f,sizeof(LL)*(n+1));
di[0]=0;
for(int l=1,r=1+(m>1);l<=m;l=r+1,r=r+2)
{
r=min(r,m);
int dx=a[l+1]-a[l];
while(r<m&&dx==a[r+1]-a[r]) ++r;
memset(d2,0x3f3f3f,sizeof(LL)*(a[l]+1));
for(int i=0;i<sz;++i)
d2[di[i]%a[l]]=min(d2[di[i]%a[l]],di[i]);
memcpy(di,d2,sizeof(LL)*(a[l]+1));
int jp=gcd(sz,a[l]),zz=sz%a[l];;
for(int i=0;i<jp;++i)
{
int np=i;
for(int j=ad(i,zz,a[l]);j!=i;j=ad(j,zz,a[l]))
if(di[np]>di[j]) np=j;
for(int j=ad(np,zz,a[l]),ls=np;j!=np;j=ad(j,zz,a[l]),ls=ad(ls,zz,a[l]))
di[j]=min(di[j],di[ls]+sz);
}
sz=a[l];
if(l==r) continue;
jp=gcd(sz,dx),zz=dx%sz;
for(int i=0;i<jp;++i)
{
int np=i;
for(int j=ad(i,zz,sz);j!=i;j=ad(j,zz,sz))
if(di[np]>di[j]) np=j;
hd=1,q[tl=1][0]=di[np],q[tl][1]=0;
for(int j=ad(np,zz,sz),k=1;j!=np;j=ad(j,zz,sz),++k)
{
while(hd<=tl&&k-q[hd][1]>r-l) ++hd;
if(hd<=tl) di[j]=min(di[j],q[hd][0]+sz+1ll*dx*k);
while(hd<=tl&&q[tl][0]>=di[j]-1ll*dx*k) --tl;
q[++tl][0]=di[j]-1ll*dx*k,q[tl][1]=k;
}
}
}
LL ans=0;
for(int i=0;i<sz;++i) ans+=max((ln-di[i]+sz)/sz,0ll);
printf("%lld\n",ans);
}
return 0;
}

luogu P4156 [WC2016]论战捆竹竿的更多相关文章

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

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

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

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

  3. BZOJ4406 WC2016 论战捆竹竿

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

  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. CF932G Palindrome Partition(回文自动机)

    CF932G Palindrome Partition(回文自动机) Luogu 题解时间 首先将字符串 $ s[1...n] $ 变成 $ s[1]s[n]s[2]s[n-1]... $ 就变成了求 ...

随机推荐

  1. QML学习笔记(一)-防止鼠标穿透事件

    作者: 狐狸家的鱼 Github: 八至 1.防止鼠标穿透 MouseArea{ anchors.fill: parent; onClicked: {}; onReleased: {}; onPres ...

  2. Java 存储时间戳的几种方式

    有时需要记录一下数据生成时间的时间戳,精确到秒,这里记录一下java存储时间戳字符串的几种方式 1.DateFormat private static final SimpleDateFormat s ...

  3. python 字典的定义以及方法

    7.字典的转换: dict(x=1,y=2)  ==>  {'y': 2, 'x': 1} dict([(i,element) for i, element in enumerate(['one ...

  4. 精读Hadamard Response论文

    一.摘要 主要研究问题基于本地化差分隐私的k-分布,之前最佳的算法要求的是线性通信代价(k),而服务器计算时间的n*k,n表示所有的用户样本. 作者提出的HR不要求共享随机性,并且每个用户输入的数据都 ...

  5. linux driver ------ platform模型,驱动开发分析

    一.platform总线.设备与驱动 在Linux 2.6 的设备驱动模型中,关心总线.设备和驱动3个实体,总线将设备和驱动绑定.在系统每注册一个设备的时候,会寻找与之匹配的驱动:相反的,在系统每注册 ...

  6. npm总是报错:unable to verify the first certificate

    今天npm install总是报错:unable to verify the first certificate(无法验证第一证书),查了一下发现 As of February 27, 2014, n ...

  7. flask blueprint

    在使用flask进行一个项目编写的时候,可能会有许多个模块,如一个网站的前台(home)和后台(admin)模块,如果把这两个模块都放在一个views.py文件之中,那么最后views.py文件必然臃 ...

  8. composer 更换国内镜像源

    使用 Composer 镜像加速有两种选项: 选项一:全局配置,这样所有项目都能惠及(推荐):选项二:单独项目配置: 选项一.全局配置(推荐) $ composer config -g repo.pa ...

  9. java io系列10之 FilterInputStream

    FilterInputStream 介绍 FilterInputStream 的作用是用来“封装其它的输入流,并为它们提供额外的功能”.它的常用的子类有BufferedInputStream和Data ...

  10. DirectX11 With Windows SDK--03 索引缓冲区、常量缓冲区

    前言 一个立方体有8个顶点,然而绘制一个立方体需要画12个三角形,如果按照前面的方法绘制的话,则需要提供36个顶点,而且这里面的顶点数据会重复4次甚至5次.这样的绘制方法会占用大量的内存空间. 接下来 ...