前言
一言以蔽之,动态DP就是随时更新转移状态的DP。
练习
难度递增。
[HDU5068] Harry And Math Teacher
[CF1380F Strange Addition] Strange Addition
讲解
核心思路是用矩阵来做DP,列出DP转移方程后用矩阵维护,具体题目具体分析。
如果你矩阵加速学得很好,那么理解动态DP就易如反掌了。
如果你连矩阵乘法都没学过,那么请出门左转学习矩阵乘法。
[HDU5068] Harry And Math Teacher
很显然的板题,考虑线段树维护转移矩阵。
[CF1380F Strange Addition] Strange Addition
详情见代码注释。
还在写。
代码
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}
*/