题意:
现在有一种加法,假设上面是1,下面是b,那么他们相加得到的c是这个样子的:
现在给你一个数组c,并且有多次修改每个位置的数字是什么,问你每次修改完之后,问你a+b=c有多少种a,b数组
题解:
假设这个数组是a,设b[i]=a[i-1]*10+a[i]
设v[i]表示当前值为i的时候,有多少种加法方式
那么可以写出dp[i]=dp[i+1]*v[a[i]]+dp[i-2]*v[b[i]]
但是有修改,所以不能直接做,由于是单点修改,那么此时我们可以将其放到线段树当中,在上传时重载*号,计算答案即可。
可以发现是这样一个矩阵
[
v
[
a
[
i
]
]
v
[
b
[
i
]
]
1
0
]
[
f
[
i
−
1
]
f
[
i
−
2
]
]
\left[ \begin{matrix} v[a[i]] & v[b[i]] \\ 1 & 0 \end{matrix} \right] \left[ \begin{matrix} f[i-1] \\ f[i-2] \end{matrix} \right]
[v[a[i]]1v[b[i]]0][f[i−1]f[i−2]]
那么我们线段树优化的时候,只需要将左边那个矩阵当中的乘起来就行了,注意需要从右往左去做。
代码是队友敲得啦,思想是这么个思想
//#pragma GCC optimize(3)
//#include<ext/pb_ds/assoc_container.hpp>
//#include<ext/pb_ds/hash_policy.hpp>
#include<bits/stdc++.h>
#define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i<(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define perr(i,a,b) for(int i=(a);i>(b);i--)
#define pb push_back
#define eb emplace_back
#define mst(a,b) memset(a,b,sizeof(a))
using namespace std;
//using namespace __gnu_pbds;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> P;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const double eps=1e-12;
const double PI=acos(-1.0);
const double angcst=PI/180.0;
const ll mod=998244353;
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll qmul(ll a,ll b){ll r=0;while(b){if(b&1)r=(r+a)%mod;b>>=1;a=(a+a)%mod;}return r;}
ll qpow(ll a,ll n){ll r=1;while(n){if(n&1)r=(r*a)%mod;n>>=1;a=(a*a)%mod;}return r;}
ll qpow(ll a,ll n,ll p){ll r=1;while(n){if(n&1)r=(r*a)%p;n>>=1;a=(a*a)%p;}return r;}
struct rect
{
ll a,b,c,d;
rect(){}
rect(ll a,ll b,ll c,ll d):a(a),b(b),c(c),d(d){}
rect operator * (const rect &r) const
{
return rect(
(a*r.a+b*r.c)%mod,(a*r.b+b*r.d)%mod
,(c*r.a+d*r.c)%mod,(c*r.b+d*r.d)%mod
);
}
};
char str[500050];
int a[500050],b[500050];
int v[666];
ll dp[500050];
rect tree[500050<<2];
void push_up(int p)
{
tree[p]=tree[p<<1|1]*tree[p<<1];
}
void buildTree(int p,int l,int r)
{
if(l==r)
{
tree[p]=rect(v[a[l]],a[l-1]==1?v[b[l]]:0,1,0);
return;
}
int mid=(l+r)>>1;
buildTree(p<<1|1,mid+1,r);
buildTree(p<<1,l,mid);
push_up(p);
}
void update(int p,int l,int r,int pos)
{
if(l==r)
{
tree[p]=rect(v[a[l]],a[l-1]==1?v[b[l]]:0,1,0);
return;
}
int mid=(l+r)>>1;
if(pos<=mid)
update(p<<1,l,mid,pos);
else
update(p<<1|1,mid+1,r,pos);
push_up(p);
}
void solve()
{
int n,m;
cin>>n>>m;
cin>>str+1;
rep(i,1,n)
a[i]=str[i]-'0';
rep(i,2,n)
b[i]=a[i-1]*10+a[i];
rep(i,0,9)
v[i]=i+1;
rep(i,10,18)
v[i]=19-i;
buildTree(1,1,n);
while(m--)
{
int p,v;
cin>>p>>v;
a[p]=v;
b[p]=a[p-1]*10+a[p];
b[p+1]=a[p]*10+a[p+1];
update(1,1,n,p);
if(p!=n)
update(1,1,n,p+1);
cout<<tree[1].a<<'\n';
}
}
int main()
{
closeSync;
//multiCase
{
solve();
}
return 0;
}