给你一个 的矩阵,行列从 1 开始标号,第 i 行 j 列的值是
现在要求你实现以下操作。
- 交换两行。
- 交换两列。
- 求一个子矩阵的做 k 次前缀和之后的和,对
取模
- 题解
首先表示的数为
,那么可以看成是
,这样交换两行或是两列就是
数组中简单的交换
考虑一个点对整个和的贡献,这个贡献就是从每次朝
可以是本身的方向走
步到
的概率,发现
依然是独立的,那么方案数可以看成
其中,可以列求和,那么现在的问题就是快速求这么一个东西:
一个套路是把组合数转成下降幂再转自然幂
然后用化简
发现我们可以处理出
的系数,那么我们用数据结构维护
就可以了
单点修改区间查询,练了一波线段树
询问复杂度
比较巧妙的地方是对 分别考虑,不好直接维护的东西转成多项式维护每一项的系数
#include<bits/stdc++.h>
#define cs const
using namespace std;
int read(){
int cnt = 0, f = 1; char ch = 0;
while(!isdigit(ch)){ ch = getchar(); if(ch == '-') f = -1; }
while(isdigit(ch)) cnt = cnt*10 + (ch-'0'), ch = getchar();
return cnt * f;
}
cs int N = 1e5 + 50, K = 15;
cs int Mod = 1e9 + 7;
int add(int a, int b){ return a + b >= Mod ? a + b - Mod : a + b; }
int mul(int a, int b){ return 1ll * a * b % Mod; }
int dec(int a, int b){ return a - b < 0 ? a - b + Mod : a - b; }
int ksm(int a, int b){ int ans = 1; for(;b;b>>=1,a=mul(a,a)) if(b&1) ans = mul(ans,a); return ans; }
void Add(int &a, int b){ a = add(a, b); }
void Dec(int &a, int b){ a = dec(a, b); }
void Mul(int &a, int b){ a = mul(a, b); }
int sgn(int a){ return a & 1 ? Mod - 1 : 1; }
int n, m, q, A[N], B[N];
int C[K][K], S[K][K], fac[N], ifac[N];
int Binom(int n, int m){ if(n<0||m<0||n<m) return 0; return mul(fac[n],mul(ifac[n-m],ifac[m])); }
void prework(int n, int m){
C[0][0] = S[0][0] = fac[0] = fac[1] = ifac[0] = ifac[1] = 1;
for(int i = 2; i <= m; i++) fac[i] = mul(fac[i-1], i);
ifac[m] = ksm(fac[m], Mod-2);
for(int i = m-1; i >= 2; i--) ifac[i] = mul(ifac[i+1], i+1);
for(int i = 1; i <= n; i++){
C[i][0] = 1;
for(int j = 1; j <= i; j++) C[i][j] = add(C[i-1][j], C[i-1][j-1]);
for(int j = 1; j <= i; j++) S[i][j] = add(S[i-1][j-1], mul(i-1, S[i-1][j]));
}
}
struct ZKW{
int vl[N<<2], M;
void build(int *a, int deg){
for(M=1;M<=deg;M<<=1);
for(int i=M+1; i<=M+deg; i++) vl[i]=a[i-M];
for(int i=M-1; i; i--) vl[i] = add(vl[i<<1], vl[i<<1|1]);
}
void modify(int x, int v){
vl[x+=M] = v;
for(x>>=1; x; x>>=1) vl[x] = add(vl[x<<1], vl[x<<1|1]);
}
int query(int l, int r){
int ans = 0;
for(l+=M-1,r+=M+1; l^r^1; l>>=1, r>>=1){
if(l&1^1) Add(ans, vl[l^1]);
if(r&1) Add(ans, vl[r^1]);
} return ans;
}
}Tx[11], Ty[11];
void build(){
static int a[N], b[N];
for(int i = 1; i <= n; i++) a[i] = A[i] = mul(i-1, m);
for(int i = 1; i <= m; i++) b[i] = B[i] = i;
for(int x = 0; x <= 10; x++){
Tx[x].build(a, n);
Ty[x].build(b, m);
for(int i = 1; i <= n; i++) Mul(a[i],dec(0,i));
for(int i = 1; i <= m; i++) Mul(b[i],dec(0,i));
}
}
int query(){
static int coe_x[K], coe_y[K];
memset(coe_x, 0, sizeof(coe_x));
memset(coe_y, 0, sizeof(coe_y));
int x1 = read(), y1 = read(), x2 = read(), y2 = read(), k = read();
for(int i = 0; i <= k; i++){
int coe = mul(ifac[k], mul(sgn(k-i), S[k][i]));
for(int j = 0, px = 1, py = 1; j <= i; j++, Mul(px, x2+k), Mul(py, y2+k)){
Add(coe_x[i-j], mul(coe, mul(C[i][j],px)));
Add(coe_y[i-j], mul(coe, mul(C[i][j],py)));
}
}
int Sx0 = 0, Sx1 = 0, Sy0 = 0, Sy1 = 0;
for(int i = 0; i <= k; i++){
Add(Sx1, mul(Tx[i].query(x1,x2), coe_x[i]));
Add(Sy1, mul(Ty[i].query(y1,y2), coe_y[i]));
} Sx0 = Binom(x2-x1+k+1, k+1); Sy0 = Binom(y2-y1+k+1,k+1);
int ans = add(mul(Sx0,Sy1),mul(Sy0,Sx1));
cout << ans << '\n';
}
void Swap_row(){
int x = read(), y = read();
swap(A[x], A[y]);
for(int i = 0, coe_x = 1, coe_y = 1; i <= 10; i++){
Tx[i].modify(x, mul(A[x],coe_x));
Tx[i].modify(y, mul(A[y],coe_y));
Mul(coe_x, dec(0,x)); Mul(coe_y, dec(0,y));
}
}
void Swap_clm(){
int x = read(), y = read();
swap(B[x], B[y]);
for(int i = 0, coe_x = 1, coe_y = 1; i <= 10; i++){
Ty[i].modify(x, mul(B[x],coe_x));
Ty[i].modify(y, mul(B[y],coe_y));
Mul(coe_x, dec(0,x)); Mul(coe_y, dec(0,y));
}
}
int main(){
n = read(), m = read(), q = read();
prework(10, 1e5 + 10);
build(); char op[3];
while(q--){
scanf("%s", op);
if(op[0] == 'Q') query();
if(op[0] == 'R') Swap_row();
if(op[0] == 'C') Swap_clm();
} return 0;
}