• 动态DP


    前言

    一言以蔽之,动态DP就是随时更新转移状态的DP。

    练习

    难度递增。

    [HDU5068] Harry And Math Teacher

    [CF1380F Strange Addition] Strange Addition

    [洛谷P5024] 保卫王国

    讲解

    核心思路是用矩阵来做DP,列出DP转移方程后用矩阵维护,具体题目具体分析。

    如果你矩阵加速学得很好,那么理解动态DP就易如反掌了。

    如果你连矩阵乘法都没学过,那么请出门左转学习矩阵乘法。

    [HDU5068] Harry And Math Teacher

    很显然的板题,考虑线段树维护转移矩阵。

    [CF1380F Strange Addition] Strange Addition

    详情见代码注释。

    [洛谷P5024] 保卫王国

    还在写。

    代码

    Harry And Math Teacher

    struct Matrix 
    {
    	int n,m,a[2][2];
    	
    	Matrix(){memset(a,0,sizeof(a));}
    	
    	Matrix operator * (const Matrix &C)
    	{
    		Matrix ret; ret.n = n; ret.m = C.m;
    		for(int i = 0;i < n;++ i)
    			for(int k = 0;k < m;++ k)
    				if(a[i][k])
    					for(int j = 0;j < C.m;++ j)
    						ret.a[i][j] = (1ll * a[i][k] * C.a[k][j] + ret.a[i][j]) % MOD;
    		return ret;
    	}
    	
    	void clr(){n = 2;m = 2;a[0][0] = a[0][1] = a[1][0] = a[1][1] = 1;}
    }I,dz;
    
    #define lc (x<<1)
    #define rc (x<<1|1)
    struct SegmentTree
    {
    	Matrix t[MAXN << 2];
    	
    	void Build(int x,int l,int r) 
    	{
    		if(l == r)
    		{
    			t[x].clr();
    			return;
    		}
    		int mid = (l+r) >> 1;
    		Build(lc,l,mid); Build(rc,mid+1,r);
    		t[x] = t[lc] * t[rc];
    	}
    	
    	void update(int x,int l,int r,int pos,int tox,int toy)
    	{
    		if(l == r)
    		{
    			t[x].a[tox][toy] ^= 1;
    			return;
    		}
    		int mid = (l+r) >> 1;
    		if(pos <= mid) update(lc,l,mid,pos,tox,toy);
    		else update(rc,mid+1,r,pos,tox,toy);
    		t[x] = t[lc] * t[rc];
    	}
    	
    	Matrix Query(int x,int l,int r,int ql,int qr)
    	{
    		if(ql <= l && r <= qr) return t[x];
    		int mid = (l+r) >>1;
    		Matrix ret = I;
    		if(ql <= mid) ret = ret * Query(lc,l,mid,ql,qr);
    		if(mid+1 <= qr) ret = ret * Query(rc,mid+1,r,ql,qr);
    		return ret;
    	}
    }st;
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	I.n = I.m = 2;
    	I.a[0][0] = I.a[1][1] = 1;
    	dz.n = 1; dz.m = 2;
    	dz.a[0][0] = dz.a[0][1] = 1;
    	while(~scanf("%d",&N))
    	{
    		st.Build(1,1,N);
    		for(int Q = Read(); Q ;-- Q)
    		{
    			if(Read()) //update
    			{
    				int x = Read(),y = Read() - 1,z = Read()-1;
    				st.update(1,1,N,x+1,y,z);
    			}
    			else //query
    			{
    				int l = Read(),r = Read();
    				Matrix ans = dz * st.Query(1,1,N,l+1,r);
    				Put((ans.a[0][0] + ans.a[0][1]) % MOD,'
    ');
    			}
    		}
    	}
    	return 0;
    }
    

    Strange Addition

    struct Matrix
    {
    	int n,m,a[3][3];
    	
    	Matrix(){memset(a,0,sizeof(a));}
    	
    	void update(int x)
    	{
    		n = 3; m = 3;
    		a[0][0] = x+1; a[0][1] = 9 - x;
    		a[1][0] = (x == 1);
    		a[2][2] = 1;
    	}
    	
    	Matrix operator * (const Matrix &C)
    	{
    		Matrix ret; ret.n = n; ret.m = C.m;
    		for(int i = 0;i < n;++ i)
    			for(int k = 0;k < m;++ k)
    				for(int j = 0;j < C.m;++ j)
    					ret.a[i][j] = (1ll * a[i][k] * C.a[k][j] + ret.a[i][j]) % MOD;
    		return ret;
    	}
    };
    
    int Get()
    {
    	char c = getchar();
    	while(c > '9' || c < '0') c = getchar();
    	return c - '0';
    }
    
    #define lc (x<<1)
    #define rc (x<<1|1)
    struct SegmentTree
    {
    	Matrix t[MAXN << 2];
    	
    	void up(int x)
    	{
    		t[x] = t[lc] * t[rc];
    	}
    	
    	void Build(int x,int l,int r)
    	{
    		if(l == r)
    		{
    			t[x].update(Get());	
    			return ;
    		}
    		int mid = (l+r) >> 1;
    		Build(rc,mid+1,r); Build(lc,l,mid); 
    		up(x);
    	}
    	
    	void Modify(int x,int l,int r,int pos,int val)
    	{
    		if(l == r)
    		{
    			t[x].update(val);
    			return;
    		}
    		int mid = (l+r) >> 1;
    		if(pos <= mid) Modify(lc,l,mid,pos,val);
    		else Modify(rc,mid+1,r,pos,val);
    		up(x);
    	}
    }st;
    
    int main()
    {
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	N = Read(); M = Read();
    	st.Build(1,1,N);
    	for(int i = 1;i <= M;++ i)
    	{
    		int p = Read();
    		st.Modify(1,1,N,N-p+1,Read());
    		Matrix ans; ans.n = 1; ans.m = 3;
    		ans.a[0][0] = 1; ans.a[0][2] = 1;
    		ans = ans * st.t[1];
    		Put(ans.a[0][0],'
    ');
    	}
    	return 0;
    }
    /*
    dp[i][0/1] 表示第i位是否给下一位提供1的方案数 
    显然答案为dp[n][0] 
    dp[i][0]=dp[i-1][0]*(a[i]+1)+(a[i]==1)*dp[i-1][1]
    dp[i][1]=(9-a[i])*dp[i-1][0]
    
    {cnt0,cnt1,1}
    
    {  a[i]+1 ,9-a[i],0
     (a[i]==1),  0   ,0
         0    ,  0   ,1}
    */
    
  • 相关阅读:
    SQL第一讲
    CSS3补充内容
    EXCEL数据导入SQL表的方法
    jq第四讲+实例
    jq第三讲
    jq第二讲
    安卓、苹果日历同步
    安卓、苹果手机备忘录同步
    服务器、客户端双认证
    今天我的博客正式开张了!
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/14556369.html
Copyright © 2020-2023  润新知