智乃酱的双塔问题
题目描述
题解
不妨先不考虑询问,求从底层到顶层的方案
设\(dp_{i,j}\)表示到第i层的j边的方案数(j=0/1,0代表在左边,1代表在右边)
转移方程为
\(dp_{i,0}=dp_{i-1,0}+[有‘\’的楼梯]\cdot dp_{i-1,1}\)
\(dp_{i,1}=dp_{i-1,1}+[有‘/’的楼梯]\cdot dp_{i-1,0}\)
不难写出一个矩阵
\[\begin{pmatrix}
dp_{i-1,0}&dp_{i-1,1}\\
\end{pmatrix}
*\begin{pmatrix}
1&[if \quad '/']\\
[if\quad '\']&1\\
\end{pmatrix}
= \begin{pmatrix}
dp_{i,0}&dp_{i,1}\\
\end{pmatrix}
\]
因此可见每一层的转移都是固定的,那么我们可以用前缀和来维护
所以对于每次询问,只要求得区间的矩阵乘积即可
得到区间的矩阵乘积可以用线段树维护,也可以直接用矩阵求逆来求,这里用的是前者
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=1e9+7;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Matrix{
int l,r;
ll a[3][3];
Matrix (){
l=2,r=2;
for(int i=0;i<l;i++){
for(int j=0;j<r;j++)a[i][j]=(i==j);
}
}
void zero(){memset(a,0,sizeof(a));}
Matrix operator*(Matrix m1){
Matrix m;m.zero();
for(int i=0;i<l;i++){
for(int j=0;j<r;j++){
for(int k=0;k<r;k++){
(m.a[i][j]+=a[i][k]*m1.a[k][j]%MOD)%=MOD;
}
}
}
return m;
}
Matrix operator+(Matrix m1){
Matrix m;m.zero();
for(int i=0;i<l;i++){
for(int j=0;j<r;j++){
(m.a[i][j]+=(a[i][j]+m1.a[i][j])%MOD)%=MOD;
}
}
return m;
}
Matrix operator^(ll y){
Matrix sum,x;
memcpy(x.a,a,sizeof(a));
while(y){
if(y&1)sum=sum*x;
y>>=1;x=x*x;
}
return sum;
}
void print(){
for(int i=0;i<l;i++){
for(int j=0;j<r;j++)printf("%lld ",a[i][j]);
printf("\n");
}
}
}ls[2];
int n,m,biao[maxn];
struct tree{
Matrix sum;
}tr[maxn];
void build(int k,int l,int r){
if(l==r){
tr[k].sum=ls[biao[l]];
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
return ;
}
Matrix query(int k,int l,int r,int L,int R){
Matrix now;
if(L>r || l>R)return now;
if(L<=l && r<=R)return tr[k].sum;
int mid=(l+r)>>1;
now=query(k<<1,l,mid,L,R)*query(k<<1|1,mid+1,r,L,R);
return now;
}
int main(){
n=read();m=read();char ch[maxn];scanf("%s",ch);
ls[0].a[0][1]=1;ls[1].a[1][0]=1;
for(int i=1;i<n;i++){
if(ch[i-1]=='/')biao[i]=0;
else biao[i]=1;
}
build(1,1,n-1);
while(m--){
int hs=read(),ht=read(),ps=read(),pt=read();
Matrix y;y.l=1;
if(ps==1)y.a[0][0]=0,y.a[0][1]=1;
Matrix now=query(1,1,n-1,hs,ht-1);
Matrix ans=y*now;
printf("%lld\n",ans.a[0][pt]);
}
return 0;
}
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=1e9+7;
const int inf=2147483647;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Matrix{
int l,r;
ll a[3][3];
Matrix (){
l=2,r=2;
for(int i=0;i<l;i++){
for(int j=0;j<r;j++)a[i][j]=(i==j);
}
}
void zero(){memset(a,0,sizeof(a));}
Matrix operator*(Matrix m1){
Matrix m;m.zero();
for(int i=0;i<l;i++){
for(int j=0;j<r;j++){
for(int k=0;k<r;k++){
(m.a[i][j]+=a[i][k]*m1.a[k][j]%MOD)%=MOD;
}
}
}
return m;
}
Matrix operator+(Matrix m1){
Matrix m;m.zero();
for(int i=0;i<l;i++){
for(int j=0;j<r;j++){
(m.a[i][j]+=(a[i][j]+m1.a[i][j])%MOD)%=MOD;
}
}
return m;
}
Matrix operator^(ll y){
Matrix sum,x;
memcpy(x.a,a,sizeof(a));
while(y){
if(y&1)sum=sum*x;
y>>=1;x=x*x;
}
return sum;
}
void print(){
for(int i=0;i<l;i++){
for(int j=0;j<r;j++)printf("%lld ",a[i][j]);
printf("\n");
}
}
}ls[2];
int n,m,biao[maxn];
struct tree{
Matrix sum;
}tr[maxn];
void build(int k,int l,int r){
if(l==r){
tr[k].sum=ls[biao[l]];
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
return ;
}
void update(int k,int l,int r,int P,int now){
if(l>P || r<P)return ;
if(l==r){
tr[k].sum=ls[now];
return ;
}
int mid=(l+r)>>1;
update(k<<1,l,mid,P,now);update(k<<1|1,mid+1,r,P,now);
tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
return ;
}
Matrix query(int k,int l,int r,int L,int R){
Matrix now;
if(L>r || l>R)return now;
if(L<=l && r<=R)return tr[k].sum;
int mid=(l+r)>>1;
now=query(k<<1,l,mid,L,R)*query(k<<1|1,mid+1,r,L,R);
return now;
}
int main(){
n=read();m=read();char ch[maxn];scanf("%s",ch);
ls[0].a[0][1]=1;ls[1].a[1][0]=1;
for(int i=1;i<n;i++){
if(ch[i-1]=='/')biao[i]=0;
else biao[i]=1;
}
build(1,1,n-1);
while(m--){
int op=read();
if(op==1){
int hs=read(),ht=read(),ps=read(),pt=read();
Matrix y;y.l=1;
if(ps==1)y.a[0][0]=0,y.a[0][1]=1;
Matrix now=query(1,1,n-1,hs,ht-1);
Matrix ans=y*now;
printf("%lld\n",ans.a[0][pt]);
}
else {
int kk=read();
char cc[2];scanf("%s",cc);
int now=0;
if(cc[0]!='/')now=1;
update(1,1,n-1,kk,now);
}
}
return 0;
}
DDP
将矩阵乘法看作floyd来求最短距离,注意初始化矩阵与单位矩阵不同
点击查看代码
#include<functional>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<complex>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<queue>
#include<deque>
#include<stack>
#include<map>
#define ll long long
#define pa pair<int,int>
using namespace std;
const int maxn=2e6+101;
const int MOD=1e9+7;
const ll inf=1LL<<61;
const double pi=acos(-1);
int read(){
int x=0,f=1;char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';
return x*f;
}
struct Matrix{
int l,r;
ll a[3][3];
Matrix (){
l=2,r=2;
//初始化不同
for(int i=0;i<l;i++){
for(int j=0;j<r;j++)a[i][j]=inf;
a[i][i]=0;
}
}
void init(){
for(int i=0;i<l;i++){
for(int j=0;j<r;j++)a[i][j]=inf;
}
}
Matrix operator*(Matrix m1){
//FLoyd
Matrix m;m.init();
for(int i=0;i<l;i++){
for(int j=0;j<r;j++){
for(int k=0;k<r;k++){
if(a[i][k]==inf || m1.a[k][j]==inf)continue;
m.a[i][j]=min(m.a[i][j],(a[i][k]+m1.a[k][j]));
}
}
}
return m;
}
void update(ll a1,ll a2,ll a3,ll a4){
a[0][0]=a1;a[0][1]=a2;
a[1][0]=a3;a[1][1]=a4;
}
};
int n,m,biao[maxn];
char ch[maxn];
ll val[maxn][4];
struct tree{Matrix sum;}tr[maxn];
void build(int k,int l,int r){
if(l==r){
if(ch[l]=='/')tr[k].sum.update(val[l][0],val[l][2],inf,val[l][1]);
else tr[k].sum.update(val[l][0],inf,val[l][2],val[l][1]);
return ;
}
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
return ;
}
void update(int k,int l,int r,int P){
if(l>P || r<P)return ;
if(l==r){
if(ch[l]=='/')tr[k].sum.update(val[l][0],val[l][2],inf,val[l][1]);
else tr[k].sum.update(val[l][0],inf,val[l][2],val[l][1]);
return ;
}
int mid=(l+r)>>1;
update(k<<1,l,mid,P);update(k<<1|1,mid+1,r,P);
tr[k].sum=tr[k<<1].sum*tr[k<<1|1].sum;
return ;
}
Matrix query(int k,int l,int r,int L,int R){
Matrix now;
if(L>r || l>R)return now;
if(L<=l && r<=R)return tr[k].sum;
int mid=(l+r)>>1;
now=query(k<<1,l,mid,L,R)*query(k<<1|1,mid+1,r,L,R);
return now;
}
int main(){
n=read();m=read();scanf("%s",ch+1);
for(int i=1;i<n;i++){
val[i][0]=read();val[i][1]=read();val[i][2]=read();
}
build(1,1,n-1);
while(m--){
int op=read();
if(op==2){
int hs=read(),ht=read(),ps=read(),pt=read();
Matrix ans=query(1,1,n-1,hs,ht-1);
if(ans.a[ps][pt]==inf)ans.a[ps][pt]=-1;
printf("%lld\n",ans.a[ps][pt]);
}
else if(op==0){
int hh=read();cin>>ch[hh];
update(1,1,n-1,hh);
}
else {
int hh=read();
val[hh][0]=read();val[hh][1]=read();val[hh][2]=read();
update(1,1,n-1,hh);
}
}
return 0;
}