t2,对题解的一些补充说明和证明。
题解写的很玄,我来补一发,我完全没有用大眼观察法。
这里解释一下为什么 是正确的。
有的哥们可能会以为这个玩意的计数会和字符串的性质,比如 border 什么的,有一点关系,而且如果从容斥的角度上来讲的话这玩意还真的不是太好证明的。
我们需要写一个动态规划 表示构建字符串长 已经匹配到 的方案数,这个 一写出来就可以发现不管字符串是什么只要 和字符串长度固定,答案一定是固定的。
然后既然答案是永远不变的,那我们不妨考虑特殊情况,那显然所有情况和特殊情况的答案都是相等的。
我们考虑 然后每次钦定一个匹配的最早结束位置,然后可以得到一个和式,把这个和式化简一下可以变成一个递推式子。
然后再根据 ,不同长度的级别是 种的,直接预处理这个数列即可。
最后随便写个数据结构维护一下,因为我比较懒所以我写了个分块。
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
int pre[800][100005];
#define int long long
const int mod = 998244353;
int n,q;
int a[100005],s[100005];
int l[1005],r[1005],be[100005],pro[1005],val[100005],pw[100005],mx[100005];
int jie[100005],inv[100005];
vector<int>p;
int qp(int p,int q){
int ans = 1,pro = p;
while(q){
if(q&1)ans = ans*pro%mod;
pro =pro*pro%mod;q>>=1;
}return ans;
}int niyuan(int x){
return qp(x,mod-2);
}inline int C(int n,int m){
return jie[n]*inv[m]%mod*inv[n-m]%mod;
}void pre_init(){
pw[0] = jie[0] = inv[0] = 1;
for(int i = 1;i<=100000;i++)pw[i] = pw[i-1]*25%mod;
for(int i = 1;i<=100000;i++)jie[i] = jie[i-1]*i%mod;
for(int i = 1;i<=100000;i++)inv[i] = niyuan(jie[i]);
for(int i = 1;i<=n;i++)p.push_back(s[i]);
sort(p.begin(),p.end());p.erase(unique(p.begin(),p.end()),p.end());
for(int i = 1;i<=n;i++)s[i] = lower_bound(p.begin(),p.end(),s[i])-p.begin();
}
void init(){
for(int k =0 ;k<p.size();k++){
int s = p[k];
for(int i = s;i<=mx[k];i++){
pre[k][i] = (1ll*26*pre[k][i-1]+pw[i-s]*C(i-1,s-1))%mod;
}
}for(int i = 1;i<=n;i++)val[i] = pre[s[i]][a[i]];
int sq = sqrt(n);
for(int i = 1;i<=sq;i++){
l[i] = (i-1)*sq+1,r[i] = i*sq;
}r[sq] = n;
for(int i = 1;i<=sq;i++){
pro[i] = 1;
for(int j = l[i];j<=r[i];j++){
pro[i] = pro[i]*val[j]%mod;be[j] = i;
}
}return;
}inline void upd(int x){
val[x] = pre[s[x]][a[x]];pro[be[x]] = 1;
for(int i = l[be[x]];i<=r[be[x]];i++)pro[be[x]] = pro[be[x]]*val[i]%mod;
}inline int query(int x,int y){
if(be[x] == be[y]){
int pro = 1;
for(int i = x;i<=y;i++)pro = pro*val[i]%mod;
return pro;
}int p = 1;
for(int i = x;i<=r[be[x]];i++)p = p*val[i]%mod;
for(int i = l[be[y]];i<=y;i++)p = p*val[i]%mod;
for(int i = be[x]+1;i<be[y];i++)p = p*pro[i]%mod;
return p;
}
#undef int
bool aa[500005];int b[500005];int c[500005];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
//freopen("venti9.in","r",stdin);
//freopen("out.ans","w",stdout);
cin >> n>> q;
for(int i = 1;i<=n;i++){
string ss;cin >> ss;s[i] = ss.size();
}for(int i = 1;i<=n;i++)cin >> a[i];
//return 0;
pre_init();
for(int i = 1;i<=n;i++)mx[s[i]] = max(mx[s[i]],a[i]);
for(int i = 1;i<=q;i++){
cin >> aa[i] >> b[i] >> c[i];
if(aa[i] == 0)mx[s[b[i]]] = max(mx[s[b[i]]],(long long)c[i]);
}init();
for(int i = 1;i<=q;i++){
if(aa[i] == 0){
a[b[i]] = c[i];upd(b[i]);
}else{
cout << query(b[i],c[i]) << '\n';
}
}
return 0;
}
自认为实现的还是不错的。
需要注意的是这个题空间很紧,预处理的大数组要开一个 int。