【DP优化技巧】3. 线段树上(广义)矩阵乘法

例题

P9192 [USACO23OPEN] Pareidolia P


看见这种改 1 个求整体的应该想到区间信息合并和线段树上矩阵乘法。

定义 \(DP\) 状态 \(f_{i,0\sim 5}\) 表示到了第 \(i\) 应该开始匹配 \(\texttt{bessie}\) 的第 \(0\sim5\) 位(从 \(0\) 开始)。

那么转移为很好推。

那么怎么快速更改呢?

发现其实这个东西可以用矩阵转移。更改一个值就是更改他的转移矩阵。

用线段树即可!

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
//#define int long long
namespace gtx{
//	Fast IO
    inline void read(int &x){
        x = 0;int h = 1;char tmp;
        do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
        while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
        x*=h;
    }
    inline void read(char &x){do{x=getchar();}while(x==' '||x=='\n'||x=='\r');}
    inline void write(char x){putchar(x);}
    inline void write(int x){
        if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
        do st[++tot]=x%10,x/=10; while(x);
        while(tot){putchar(st[tot--]+'0');}
    }
    inline void write(int x,char y){write(x);write(y);}
#ifndef int
    inline void read(long long &x){
        x = 0;int h = 1;char tmp;
        do{tmp=getchar();if(tmp=='-')h*=-1;}while(!isdigit(tmp));
        while(isdigit(tmp)) x*=10,x+=tmp-'0',tmp=getchar();
        x*=h;
    }
    inline void write(long long x){
        if(x<0) putchar('-'),x=-x;int st[200]={0},tot=0;
        do st[++tot]=x%10,x/=10; while(x);
        while(tot){putchar(st[tot--]+'0');}
    }
    inline void write(long long x,char y){write(x);write(y);}
#endif
    const int MAXN = 2e5+10;
    long long B[10][10] = 
        {
            {0,1,0,0,0,0,0,0,0},
            {0,1,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,0,0,0},
            {0,0,0,1,0,0,0,0,0},
            {0,0,0,0,1,0,0,0,0},
            {0,0,0,0,0,1,0,0,0},
            {0,0,0,0,0,0,1,1,0},
            {0,0,0,0,0,0,0,1,0},
            {0,1,0,0,0,0,0,0,1}
        }
    ;
    long long E[10][10] = 
        {
            {1,0,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,0,0,0},
            {0,0,1,0,0,0,0,0,0},
            {0,0,0,1,0,0,0,0,0},
            {0,0,0,0,1,0,0,0,0},
            {1,0,0,0,0,0,1,1,0},
            {0,0,0,0,0,0,1,1,0},
            {0,0,0,0,0,0,0,1,0},
            {1,0,0,0,0,0,0,0,1}
        }
    ;
    long long S[10][10] = 
        {
            {1,0,0,0,0,0,0,0,0},
            {0,1,0,0,0,0,0,0,0},
            {0,0,0,1,0,0,0,0,0},
            {0,0,0,0,1,0,0,0,0},
            {0,0,0,0,1,0,0,0,0},
            {0,0,0,0,0,1,0,0,0},
            {0,0,0,0,0,0,1,1,0},
            {0,0,0,0,0,0,0,1,0},
            {1,0,0,0,0,0,0,0,1}
        
    };
    long long I[10][10] = 
        {
            {1,0,0,0,0,0,0,0,0},
            {0,1,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,0,0,0},
            {0,0,0,1,0,0,0,0,0},
            {0,0,0,0,0,1,0,0,0},
            {0,0,0,0,0,1,0,0,0},
            {0,0,0,0,0,0,1,1,0},
            {0,0,0,0,0,0,0,1,0},
            {1,0,0,0,0,0,0,0,1}
        }
    ;
    long long T[10][10] = 
        {
            {1,0,0,0,0,0,0,0,0},
            {0,1,0,0,0,0,0,0,0},
            {0,0,1,0,0,0,0,0,0},
            {0,0,0,1,0,0,0,0,0},
            {0,0,0,0,1,0,0,0,0},
            {0,0,0,0,0,1,0,0,0},
            {0,0,0,0,0,0,1,1,0},
            {0,0,0,0,0,0,0,1,0},
            {1,0,0,0,0,0,0,0,1}
        }
    ;
    struct segmentree{
        int l,r;
        long long ans[10][10];
    }tree[MAXN<<3];
    inline void pushup(int o){
		memset(tree[o].ans,0,sizeof tree[o].ans);
		for(int i = 0;i<9;i++){
			for(int j = 0;j<9;j++){
				for(int k = 0;k<9;k++){
					tree[o].ans[i][k] += tree[o*2].ans[i][j]*tree[o*2+1].ans[j][k];
				}
			}
		}
    }
    inline void build(int k,int l,int r){
        tree[k].l = l;
        tree[k].r = r;
        if(l==r) return;
        int mid = (l+r)>>1;
        build(k*2,l,mid);
        build(k*2+1,mid+1,r);
    }
    inline void modify(int k,int x,char t){
        if(tree[k].l>x||tree[k].r<x) return;
        if(tree[k].l==x&&tree[k].r==x){
            if(t=='b') memcpy(tree[k].ans,B,sizeof B);
            else if(t=='e') memcpy(tree[k].ans,E,sizeof E);
            else if(t=='i') memcpy(tree[k].ans,I,sizeof I);
            else if(t=='s') memcpy(tree[k].ans,S,sizeof S);
            else memcpy(tree[k].ans,T,sizeof T);
            return;
        }
        modify(k*2,x,t);
        modify(k*2+1,x,t);
        pushup(k);
    }
    char a[MAXN];
    int n;
    int begin[10]=
        {0,0,0,0,0,0,0,0,1}
    ;
	long long get(){
		long long ans[10] = {};
		for(int j = 0;j<9;j++){
			for(int k = 0;k<9;k++)
				ans[j] += begin[k]*tree[1].ans[k][j];
		}
		return ans[7];
	}
    signed main(){
        scanf("%s",a+1);
        n = strlen(a+1);
        build(1,1,n);
		for(int i = 1;i<=n;i++) modify(1,i,a[i]);
        write(get(),endl);
		int q;
		read(q);
		while(q--){
			int x;char y;
			read(x);read(y);
			modify(1,x,y);
			write(get(),endl);
		}
        return 0;
    }
}
signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
//	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int T = 1;
//	gtx::read(T);
    while(T--) gtx::main();
    return 0;
}
posted @ 2025-01-11 16:34  GuTongXing  阅读(28)  评论(0)    收藏  举报