Processing math: 100%

https://vjudge.net/problem/QOJ-8543

给定 n,对于 i=1,2,,n 求出最长可能的周期字符串序列长度 F(i),满足序列中字符串的长度 i。一个字符串序列 S1,S2,,Sl 是周期字符串序列,当且仅
当对于每个 1i<l 都满足 SiSi+1 的周期,并且它们两两不同。(n<=2e5)

先求单个 F(n)。

手玩几下,发现:第一个串一定是长为 n 的,并且一定是 abbbb... 形式。

:abbbb
:abbb
abbba
:abb
abbab
abba
abbaa
:ab
ababa
abab
aba
abaab
abaa
abaaa
:a
aa
aaa
aaaa
aaaaa

观察冒号处的前缀最小值。后面拖了一段串。抓 ab 领导的这一段分析:

  1. 抓出 ab 后的每一个 a 开头的串,形似整数拆分;
  2. 整数拆分是有序的;
  3. 拆分的整数都不能超过开头 ab 串的长度(2)。
  4. 被拆分的整数不超过 n-|ab|。

即求序列 x 的个数,使得 xnxix1

枚举开头 abb... 串的长度 x1=k,得 F(n) 的生成函数:

11xk1xk11ikxi=11xk1xk1xxk+11x

外面乘的 11x 是因为总和不超过 n 而不是恰好等于 n。

化简:

k1xk1(2xxk+1)

kn 时,暴力计算贡献。具体来说,不断地给初始多项式 xk 乘上 (2xxk+1),再加上 xk。可以写成完全背包转移。

k>n 时,化原式:

xk(12x)(1xk+112x)=xk12xj0(xk+112x)j=j0(1)jx(k+1)j+k(12x)j+1

显然 jn 的是有用的。j 从大到小枚举,加完贡献后乘 112x,还是完全背包转移。

看 Dairuichen007 学会的代码。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fi first
#define se second
#define mkp std::make_pair
using ll=long long;
using llu=unsigned long long;
using std::max;
using std::min;
template<class T> void cmax(T&a,T b){a=max(a,b);}
template<class T> void cmin(T&a,T b){a=min(a,b);}
const int NV=3e3;
ll mod;
namespace xm{
int N,ans[NV+5],f[NV+5],g[NV+5];
void lB(int k){
memset(f,0,sizeof f);
f[k]=1;
for(int i=k+1;i<=N;++i) f[i]=(2ll*f[i-1]+mod-f[i-k-1])%mod;
for(int i=1;i<=N;++i) ans[i]=(ans[i]+f[i])%mod;
}void _(){
scanf("%d%lld",&N,&mod);
int B=sqrt(N);
for(int i=1;i<=B;++i) lB(i);
for(int x=B;~x;--x){
for(int k=B+1;k<=N;++k){
const int i=(k+1)*x+k;
if(i<=N) g[i]=(g[i]+(x&1?mod-1:1))%mod;
}
for(int i=1;i<=N;++i) g[i]=(g[i]+2ll*g[i-1])%mod;
}
for(int i=1;i<=N;++i) ans[i]=(ans[i]+g[i])%mod;
for(int i=1;i<=N;++i) printf("%lld ",ans[i]); puts("");
}
}
int main(){
xm::_();
return 0;
}
posted on   Zaunese  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!



点击右上角即可分享
微信分享提示