Skip to main content

题解:P10116 [LMXOI Round 1] Random

· 2 min read
lailai
Student & Developer

原题链接

题意简述

初始时,长度为 nn 的序列全为 00

进行 qq 次操作:每次可以选择一个位置,将其改为 [1,k][1,k] 范围内的任意一个数。

给定一个长度为 mm 的匹配序列 B[1,k]mB\in[1,k]^m,统计在所有可能的 (nk)q(nk)^q 个结果序列中,序列 BB 出现的总次数。

解题思路

我们注意到答案与 BB 无关。固定一个长度为 mm 的窗口,窗口总数为:

nm+1n-m+1

若窗口内漏掉 ii 个格子,则可选位置为 nin-i,对应下标序列数为 (ni)q(n-i)^q,故有:

i=0m(1)i(mi)(ni)q\sum_{i=0}^{m}(-1)^i\binom{m}{i}(n-i)^q

在覆盖成立时,为使窗口最终等于给定 BB,这 mm 个格子的最后一次写入被唯一确定,其余 qmq-m 次任意,因子为:

kqmk^{q-m}

综上,最终答案为:

(nm+1)kqmi=0m(1)i(mi)(ni)q(n-m+1)\cdot k^{q-m}\cdot\sum_{i=0}^{m}(-1)^i\binom{m}{i}(n-i)^q

参考代码

#include <bits/stdc++.h>
using namespace std;

using ll=long long;
const int mod=998244353;
const int N=3000005;
ll inv[N],fac[N],jv[N];
void init()
{
fac[0]=jv[0]=1;
for(int i=1;i<N;i++)
{
inv[i]=i==1?1:(mod-mod/i)*inv[mod%i]%mod;
fac[i]=fac[i-1]*i%mod;
jv[i]=jv[i-1]*inv[i]%mod;
}
}
ll C(ll n,ll m)
{
if(n<m||m<0)return 0;
return fac[n]*jv[n-m]%mod*jv[m]%mod;
}
ll Pow(ll x,ll y)
{
x%=mod;
ll res=1;
while(y)
{
if(y&1)res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
init();
ll n,m,q,k,a,b;
cin>>n>>m>>q>>k>>a>>b;
if(q<m)
{
cout<<0<<'\n';
return 0;
}
ll sum=0;
for(int i=0;i<=m;i++)
{
sum=(sum+Pow(-1,i)*C(m,i)%mod*Pow(n-i,q)%mod)%mod;
}
ll ans=sum*Pow(k,q-m)%mod*(n-m+1)%mod;
cout<<(ans%mod+mod)%mod<<'\n';
return 0;
}