首先,这题的列数非常的小,很像矩阵快速幂加速dp。这题实际上也是维护了一段区间矩阵乘积的结果。
查询 O(1) 修改 O( logn * K^3 )
这里有一个需要注意的点是左乘和右乘的区别。矩阵快速幂还是 (1,n) *( n,n )这种形式比较好。
#include <bits/stdc++.h>
#define lc l,mid,x<<1
#define rc mid+1,r,x<<1|1
using namespace std;
typedef long long LL;
typedef int lint;
const lint mod = 1000000007;
const int maxn = 50005;
LL mul( LL a,LL b ){
a *= b; a %= mod;
return a;
}
LL ad( LL a,LL b ){
a += b; a%= mod;
return a;
}
struct matrix{
int n,m;
lint ma[11][11];
matrix operator*( const matrix& b ){
matrix c;
c.n = n;c.m = b.m;
for( int i = 1;i <= c.n;i++ ){
for( int j = 1;j <= c.m;j++ ){
c.ma[i][j] = 0;
for( int k = 1;k <= m;k++ ){
c.ma[i][j] = ad(c.ma[i][j],mul(ma[i][k] ,b.ma[k][j] ) );
}
}
}
return c;
}
};
matrix tree[4*maxn];
int m,b[maxn][11];
matrix calc( int l ){
matrix c;c.n = c.m = m;
for( int i = 1;i <= m;i++ ){
int f = 1;
for( int j = i;j <= m;j++ ){
if( b[l][j] ) f = 0;
c.ma[j][i] = f;
}
f = 1;
for( int j = i;j >= 1;j-- ){
if( b[l][j] ) f = 0;
c.ma[j][i] = f;
}
}
return c;
}
void push_up( int x ){
tree[x] = tree[x<<1]*tree[x<<1|1];
}
void build( int l,int r,int x ){
if( l == r ){
tree[x] = calc(l);
return;
}
int mid = l+r >>1;
build(lc);
build(rc);
push_up(x);
}
void update( int left,int right,const matrix& v,int l,int r,int x ){
if( left <= l && right >= r ){
tree[x] = v;
return;
}
int mid = l+r>>1;
if( left <= mid ){
update( left,right,v,lc);
}
if( right > mid ){
update( left,right,v,rc );
}
push_up(x);
}
matrix fi;
int main(){
int n,q;
scanf("%d%d%d",&n,&m,&q);
for( int i = 1;i <= n;i++ ){
for( int j = 1;j <= m;j++ ){
scanf("%1d",&b[i][j]);
}
}
build( 1,n,1 );
for( int i = 1;i <= q;i++ ){
int f,x,y;
scanf("%d%d%d",&f,&x,&y);
if( f==1 ){
b[x][y] ^= 1;
matrix c = calc(x);
update(x, x, c, 1, n, 1);
}else{
fi.n = 1;fi.m = m;
for( int i = 1;i <= m;i++ ){
fi.ma[1][i] = 0;
}
fi.ma[1][x] = 1;
matrix c = fi * tree[1];
int ans = c.ma[1][y];
printf("%d\n",ans);
}
}
return 0;
}