AT_abc335_f [ABC335F] Hop Sugoroku 题解

比 E 简单。

分析

考虑暴力 DP。

定义状态函数 fi 表示最后一个黑点为 i 时的方案数,有:fi=j=1i1fj[(ij)modvalj=0]。不难发现在使用刷表法的时候,转移代码:

for(re int j=1;i+val[i]*j<=n;++j) f[i+val[i]*j]=(f[i+val[i]*j]+f[i])%p;

这玩意复杂度是 O(nvali) 的。

又有一种 DP 方式,定义状态函数 gi,j 表示在枚举到下标 x 时,kmodi=j 的方案数。因为 amodb=cmodb 时,(ac)modb=0,所以有:fi=j=1Vgj,imodj。复杂度 O(V)

然后有个很经典的东西,叫根号分治:对于 valiV 的情况,用第二种 DP 方式,否则使用第一种。有复杂度 O(nV+nnv)V=n 时接近 O(nn)

代码

#include<bits/stdc++.h>
using namespace std;
#define re register
#define il inline
#define PII pair<int,int>
#define x first
#define y second

il int read(){
	int x=0;char ch=getchar();
	while(ch<'0'||ch>'9') ch=getchar();
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}

const int N=2e5+10,M=sqrt(N)+10,p=998244353;
int n,val[N],ans;
int f[N],g[M][M],base;

il void solve(){
	n=read(),base=sqrt(n);
	for(re int i=1;i<=n;++i) val[i]=read();
	f[1]=1;
	for(re int i=1;i<=n;++i){
		for(re int j=1;j<=base;++j) f[i]=(f[i]+g[j][i%j])%p;
		if(val[i]<=base) g[val[i]][i%val[i]]=(g[val[i]][i%val[i]]+f[i])%p;
		else for(re int j=1;i+val[i]*j<=n;++j) f[i+val[i]*j]=(f[i+val[i]*j]+f[i])%p;
		ans=(ans+f[i])%p;
	}
	printf("%d\n",ans);
	return ;
}

signed main(){
	solve();
	return 0;
}
posted @   harmis_yz  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示