1. 程式人生 > 其它 >Codeforces 1380 F. Strange Addition —— 線段樹優化矩陣快速冪

Codeforces 1380 F. Strange Addition —— 線段樹優化矩陣快速冪

技術標籤:想法2600線段樹

This way

題意:

現在有一種加法,假設上面是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[i1]f[i2]]
那麼我們線段樹優化的時候,只需要將左邊那個矩陣當中的乘起來就行了,注意需要從右往左去做。
程式碼是隊友敲得啦,思想是這麼個思想

//#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; }