专栏文章

题解:P11959 「ZHQOI R1」诗歌

P11959题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@mipue54p
此快照首次捕获于
2025/12/03 18:06
3 个月前
此快照最后确认于
2025/12/03 18:06
3 个月前
查看原文
赛时做法,不知道官方题解为什么这么复杂,赶紧来发个题解。
显然一个串是动听的充要条件是任意两个相同字符坐标差超过 m+2m+2,即任意连续 m+3m+3 个字符两两不同。
注意到开头已经给了 m+2m+2 个字符,这启示我们直接往后填,不考虑末位字符的限制,每次要求与前面 m+2m+2 个字符均不同,有 (k(m+2))n(m+2)(k-(m+2))^{n-(m+2)} 种方案。
对每种字符进行考虑,如果这个字符在开头 ii 处出现过,则只会在 i+m+3ni+m+3\sim n 这一段再次出现,将 m+3i+m+2m+3\sim i+m+2 任意填上后,转化为一个只与余下长度有关而与当前字符无关的问题。
显然可以不考虑已确定的末位字符 xx,然后考虑指定一些位置放 xx,显然相邻位置差以及与末位的差都至少为 m+2m+2,进一步地,如果一个位置之前 m+2m+2 位有 xx,直接 k(m+2)k-(m+2) 任意填,否则额外要求与 xx 不同,k(m+2)1k-(m+2)-1 种方案。
可以直接 dp,fif_i 表示前 ii 位的答案,有转移 fi=(k(m+2)1)fi1+(k(m+2))m+2fim1f_i=(k-(m+2)-1)f_{i-1}+(k-(m+2))^{m+2}f_{i-m-1}
时间复杂度 O(n+qm)O(n+qm),跑挺快的。
CPP
#include<bits/stdc++.h>
#define maxn 2010
#define int long long
using namespace std;
const int Mod=998244353,N=1e7;
inline int reduce(int x){if(x>=Mod) return x-=Mod;return x;}

int q,k,m,f[N+100],bas[maxn];
inline int query(int x){
	if(x<0) return 0;
	return f[x];
}
inline void solve(){
	int res=1;
	scanf("%lld%lld%lld",&q,&k,&m);
	m+=2;
	bas[0]=1;
	for(int i=1;i<=m;i++) bas[i]=bas[i-1]*(k-m)%Mod;
	f[0]=1;
	for(int i=1;i<=N;i++){
		if(i>m) f[i]=(f[i-1]*(k-m-1)+f[i-m-1]*bas[m])%Mod;
		else f[i]=f[i-1]*(k-m-1)%Mod;
	}
	while(q--){
		int n;
		scanf("%lld",&n);
		unordered_map<int,int>mp;
		for(int i=1,x;i<=m;i++) scanf("%lld",&x),mp[x]=i;
		int len,ans=0;
		scanf("%lld",&len);
		while(len--){
			int x;
			scanf("%lld",&x);
			if(!mp.count(x)) ans=reduce(ans+query(n-m-1));
			else ans=(ans+query(n-mp[x]-m-1)*bas[mp[x]])%Mod;
		}
		printf("%lld\n",ans);
	}
}
signed main(){
	signed C,T=1;
	scanf("%d",&C);
	while(T--) solve();
	return 0;
}

评论

0 条评论,欢迎与作者交流。

正在加载评论...