题目描述
n<=5e5,w<=1e18,T=5
题解
需要各种前置姿势的吼题
同余最短路
求形如(sum a_ix_i=A;(a_i>=0,xin N))的A的个数
做法是按找%min(a)变成min(a)*x+b来分类跑最短路,f[i]表示%min(a)=i的最小的b,最后直接统计
本题中可以用aaa...aba...aaa的串来卡成n^2,所以要优化
border
定义next[i]为KMP中的next数组,当S[1...x]=S[|S|-x+1...S]时称S[1...x]为S的一个border
如果有S[i]=S[i+a],则a是S的一个周期,显然一个长度为x的border的周期为|S|-x,同理一个为x的周期一定对应一个长度为|S|-x的border
border的性♂质:一个串所有border的周期长度可以分成log个等差数列
证明:
对于长度>=|当前S|/2(小于一半会有问题)的border,设A是其中最长的(即周期最小),B是除A外任意一个
设p=|S|-|A|,q=|S|-|B|,则gcd(p,q)显然也是一个周期
因为gcd(p,q)<=|S|-|A|,所以有|S|-gcd(p,q)>=|A|
又因为A是最长的border,所以有|S|-gcd(p,q)<=|A|
因此|S|-gcd(p,q)=|A|,即gcd(p,q)=p,因此增加新的B不会产生新的周期,同时一定会形成一个等差数列(kp还是一个周期)
然后以<|S|/2的第一个border作为新的S,剩下的border也是新串的border,每次折半所以只有log个
题解
有了border的性质就可以优化最短路了,考虑一次处理一个等差数列x,x+p,...,x+lp
发现在%x意义下分成了gcd(x,p)个环,每个环互不影响
又发现环上的最小值不会被更新,所以从最小值处把环断开变成从长度为l的一段更新,把贡献拆开用单调队列维护
于是现在求出了当前等差数列的值,考虑转移到下一个等差数列
显然是f[i]->g[f[i]%x'],但是这样没有考虑刚好为x的转移,所以在g上做一个(x=0,p=x,l=inf)的同余最短路即可得到新的值
时间复杂度O(nlogn),Extra Test需要卡一下常
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define min(a,b) (a<b?a:b)
#define ll long long
//#define file
using namespace std;
int nx[500001],A[500001],a[101][3],b[1000001],d[500001],T,n,i,j,k,l,tot,N,h,t;
ll D[500001],f[500001],g[500001],w,ans;
char st[500001];
int gcd(int x,int y) {int r=x%y; while (r) x=y,y=r,r=x%y; return y;}
void Work(ll x,ll p,int l)
{
ll mn=9223372036854775807ll,s;
int i,j,k,mn2;
fo(i,1,N) if (f[b[i]]<mn) mn=f[b[i]],mn2=i;
fo(i,1,mn2-1) b[i+N]=b[i];
fo(i,1,N) b[i]=b[i+mn2-1];
h=t=1;d[1]=1;D[1]=f[b[1]]-p;
fo(i,2,N)
{
while (h<=t && (i-d[h])>=l) ++h;
f[b[i]]=min(f[b[i]],f[b[d[h]]]+x+p*(i-d[h]));
s=f[b[i]]-p*i;
while (h<=t && D[t]>=s) --t;
d[++t]=i;D[t]=s;
}
}
void work(int n,ll x,ll p,int l)
{
int i,j,k,K;
K=gcd(n,p),N=n/K;
fo(i,0,K-1)
{
k=i;
fo(j,1,N) b[j]=k,k+=p,k-=(k>=n)?n:0;
Work(x,p,l);
}
}
int main()
{
#ifdef file
freopen("uoj172.in","r",stdin);
#endif
scanf("%d",&T);
for (;T;--T)
{
scanf("%d%lld",&n,&w);
scanf("%s",st+1);
if (w<n) {printf("0
");continue;}
fo(i,2,n)
{
nx[i]=nx[i-1];
while (nx[i] && st[i]!=st[nx[i]+1])
nx[i]=nx[nx[i]];
nx[i]+=st[i]==st[nx[i]+1];
}
l=tot=0;
for (i=nx[n]; i; i=nx[i]) A[++l]=n-i;A[++l]=n;
j=0;
fo(i,1,l)
{
j+=a[tot][1];
if (j!=A[i])
{
++tot;
a[tot][0]=A[i],a[tot][2]=1;
if (i<l)
a[tot][1]=A[i+1]-A[i],j=A[i+1],++i,a[tot][2]=2;
}
else ++a[tot][2];
}
memset(f,127,sizeof(f));
f[n%a[1][0]]=n;
fo(i,1,tot)
{
if (a[i][2]>1)
work(a[i][0],a[i][0],a[i][1],a[i][2]);
if (i<tot)
{
memset(g,127,sizeof(g));
fo(j,0,a[i][0]-1)
k=f[j]%(a[i+1][0]),g[k]=min(g[k],f[j]);
memcpy(f,g,(a[i+1][0]+1)*8);
work(a[i+1][0],0,a[i][0],n);
}
}
ans=0;
fo(i,0,a[tot][0]-1)
if (f[i]<=w)
ans=ans+((w-f[i])/a[tot][0]+1);
printf("%lld
",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}