动态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,'\n');
			}
		}
	}
	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],'\n');
	}
	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}
*/
posted @ 2021-03-27 15:42  皮皮刘  阅读(64)  评论(0编辑  收藏  举报