qoj10093 Jump the Frog

SOLUTION FROM WUMIN4

题意

给出 \(n\) 个由 O~ 组成的字符串 \(s_i\),还有 \(m\) 个额外字符串,第 \(n+i\) 个字符串 \(s_{n+i}\) 由第 \(s_x\)\(s_y\) \((x,y<n+i)\) 个字符串拼接得到,即 \(s_{n+i}=s_x+s_y\)。你需要对这 \(n+m\) 个字符串解决以下问题:

有一只青蛙从字符串的起点出发,它只能站在 O 上,且每次可以向前跳 \(1\sim k\) 格,问跳到末尾有多少种不同的方案。

\(1\le n,m\le 10^5,1\le k\le 20,\sum|s_i|\le 10^5\)

思路

我们先对前 \(n\)\(s_i\) 进行朴素 dp。设 \(f_{i}\) 为青蛙跳到第 \(i\) 格的方案数,显然有:

\[f_{i}=\begin{cases} 0 & s_i\neq 'O' \\ \sum_{j=\max(0,i-k)}^{i-1} f_{j} & s_i='O' \end{cases} \]

答案即为 \(f_{end}\)

我们解决了前 \(n\) 个字符串的答案,考虑后 \(m\) 个字符串的答案。

假如把两段字符串拼接到一起,可以发现从一个字符串跳到另一个字符串只有可能从前一个字符串的最后 \(k\) 个位置跳到后一个字符串的前 \(k\) 个位置,所以我们对每个字符串不用存储太多的信息。

于是记 \(f_{i,s,t}\) 表示从第 \(i\) 个字符串的第 \(s\) 个字符开始,跳到距离末尾 \(t\) 个字符的位置的方案数。

\(n\) 个处理方法同上,对于后 \(m\) 个,用以上思路转移,则有:

\[f_{i,s,t}=\sum_{t',s'}^{t'+s'+1\le k} f_{x,s,t'} f_{y,s',t} \]

换个形式

\[f_{i,s,t}=\sum_{s'=0}^{k-1} f_{y,s',t}\sum_{t'=0}^{k-s'-1} f_{x,s,t'} \]

发现右边一坨可以使用前缀和预处理。

注意判一下 \(s,t\) 都在第一个字符串和第二个字符串中的情况,此时可以直接转移过来。

时间复杂度 \(O((n+m)k^3)\approx 1.6 \times 10^9\),理论十分的不可过,但是它过了,而且好像是 std 复杂度。

代码

#include <bits/stdc++.h>
using namespace std;
const int md=998244353;
int n,k,m,f[200005][25][25],g[200005][25][25],sz[200005];
string s;
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>n>>k>>m;
	for(int i=1;i<=n;i++){
		cin>>s;
		sz[i]=s.length();
		for(int l=0;l<min((int)(s.length()),k);l++){
			vector<int> ff;
			for(int j=0;j<l;j++)
				ff.push_back(0);
			for(int j=l;j<s.length();j++){
				if(j==l&&s[j]=='O') ff.push_back(1);
				else ff.push_back(0);
				if(s[j]=='O'){
					for(int jj=max(j-k,l);jj<j;jj++)
						ff[j]=(1ll*ff[j]+ff[jj])%md;
				}
			}
			for(int j=max(l,(int)s.length()-k);j<s.length();j++){
				f[i][l][s.length()-j-1]=ff[j];
				g[i][l][s.length()-j-1]=f[i][l][s.length()-j-1];
				if(s.length()-j-1!=0)
					g[i][l][s.length()-j-1]=(1ll*g[i][l][s.length()-j-1]+g[i][l][s.length()-j-2])%md;
			}
			for(int j=1;j<k;j++)
				g[i][l][j]=(g[i][l][j]+g[i][l][j-1])%md;
		}
		cout<<f[i][0][0]<<" ";
	}
	for(int x,y,i=n+1;i<=n+m;i++){
		cin>>x>>y;
		sz[i]=sz[x]+sz[y];
		if(sz[i]>=k) sz[i]=k;
		for(int st=0;st<k;st++){
			for(int ed=0;ed<k;ed++){
				if(st>=sz[x])
					f[i][st][ed]=f[y][st-sz[x]][ed];
				else if(ed>=sz[y])
					f[i][st][ed]=f[x][st][ed-sz[y]];
				else for(int ss=0;ss<k&&k-ss-1>=0;ss++)
					f[i][st][ed]=(f[i][st][ed]+1ll*f[y][ss][ed]*g[x][st][k-ss-1])%md;
				g[i][st][ed]=f[i][st][ed];
				if(ed!=0)
					g[i][st][ed]=(1ll*g[i][st][ed]+g[i][st][ed-1])%md;
			}
		}
		cout<<f[i][0][0]<<" ";
	}
	return 0;
}
posted @ 2025-09-17 16:02  WuMin4  阅读(10)  评论(0)    收藏  举报