Codeforces 1380 F. Strange Addition —— 線段樹優化矩陣快速冪
阿新 • • 發佈:2020-12-10
題意:
現在有一種加法,假設上面是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;
}