省選模擬:矩陣求和(樹狀數組,組合數)

在這裏插入圖片描述

這個題。
在這裏插入圖片描述
畫出這樣一個矩形,設左邊第ii行第0列的數爲xi=(i1)mx_i = (i-1)m,上邊第ii列第00行的數爲yi=iy_i = i,就可以得到ai,j=xi+yja_{i,j} = x_i + y_j
那麼可以發現交換兩行和兩列,只需要單點修改x,yx,y這兩個數組即可。

kk次前綴和,考慮一個ai,ja_{i,j}kk次前綴和後的(a,c)>(b,d)(a,c) ->(b,d)這個矩形中總共貢獻了多少答案。
ans=i=abj=cdai,j(bi+kk)(dj+kk)ans = \sum_{i=a}^b \sum_{j=c}^d a_{i,j} * \binom{b-i+k}{k} * \binom{d-j+k}{k}
拆開變成和xi,yjx_i,y_j有關的式子:
=i=abxi(bi+kk)j=cd(dj+kk)+i=cdyi(di+kk)j=ab(bj+kk)= \sum_{i=a}^b x_i * \binom{b-i+k}{k} * \sum_{j=c}^d \binom{d-j+k}{k}\\+ \sum_{i=c}^d y_i * \binom{d-i+k}{k} * \sum_{j=a}^b \binom{b-j+k}{k}
後面那個j=ab(bj+kk)=(ba+k+1k+1)\sum_{j=a}^b \binom{b-j+k}{k} = \binom{b-a+k+1}{k+1}
所以可以進一步化簡爲:
=i=abxi(bi+kk)(dc+k+1k+1)+i=cdyi(di+kk)(ba+k+1k+1)= \sum_{i=a}^b x_i * \binom{b-i+k}{k} * \binom{d-c+k+1}{k+1}\\+ \sum_{i=c}^d y_i * \binom{d-i+k}{k} * \binom{b-a+k+1}{k+1}
考慮如何維護i=abxi(bi+kk)\sum_{i=a}^b x_i \binom{b-i+k}k
差分轉化爲維護i=1pxi(bi+kk)\sum_{i=1}^p x_i \binom{b-i+k}k
求出f(b,i,k)=(bi+kk)=x=0ky=0kcx,ybxiyf(b,i,k) = \binom{b-i+k}k = \sum_{x=0}^k \sum_{y=0}^k c_{x,y} b^x i^ycx,yc_{x,y}係數,這個可以預處理。
然後只需要樹狀數組維護求出g(p,y)i=1pxiiyg(p,y)\sum_{i=1}^px_ii^y即可O(k2)O(k^2)計算出i=1pxif(b,i,k)=i=1pu=0kv=0kcu,vbuxiiv\sum_{i=1}^p x_if(b,i,k) = \sum_{i=1}^p \sum_{u=0}^k \sum_{v=0}^k c_{u,v} b^u x_ii^v
時間複雜度O(nk(k+logn))O(nk(k+\log n))

AC Code\mathcal AC \ Code

#include<bits/stdc++.h>
#define maxn 100505
#define mod 1000000007
using namespace std;

int n,m,l[maxn],u[maxn],fac[maxn],inv[maxn],invf[maxn];
int tl[11][maxn],tu[11][maxn],P[11][11][11];
int add(int a){ return a >= mod ? a - mod : a; }
void upd(int *tr,int u,int v){ for(;u<maxn;u+=u&-u) tr[u] = add(tr[u] + v); }
int qry(int *tr,int u){ int r=0;for(;u;u-=u&-u) r=add(r+tr[u]);return r; }
int C(int a,int b){ if(a<0||b<0||a-b<0) return 0;return fac[a] * 1ll * invf[b] % mod * invf[a-b]%mod; }

int main(){
	
	freopen("1.in","r",stdin);
	freopen("1.out","w",stdout);
	
	int Q;
	scanf("%d%d%d",&n,&m,&Q);
	for(int i=1;i<=n;i++){
		l[i] = 1ll * (i-1) * m % mod;
		for(int j=0,p=l[i];j<=10;j++,p=1ll*p*i%mod)
			upd(tl[j],i,p);
	}
	for(int i=1;i<=m;i++){
		u[i] = i;
		for(int j=0,p=u[i];j<=10;j++,p=1ll*p*i%mod)
			upd(tu[j],i,p);
	}
	fac[0] = fac[1] = inv[0] = inv[1] = invf[0] = invf[1] = 1;
	for(int i=2;i<maxn;i++) fac[i] = 1ll * fac[i-1] * i % mod,
		inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod,
		invf[i] = 1ll * invf[i-1] * inv[i] % mod;
	P[0][0][0] = 1;
	for(int i=1;i<=10;i++)
		for(int j=0;j<=i;j++)
			for(int k=0;k<=i;k++){
				if(j) P[i][j][k] = add(P[i][j][k] + P[i-1][j-1][k]);
				if(k) P[i][j][k] = add(P[i][j][k] + mod - P[i-1][j][k-1]);
				P[i][j][k] = (P[i][j][k] + 1ll * P[i-1][j][k] * i) % mod;
				P[i][j][k] = 1ll * P[i][j][k] * inv[i] % mod;
			}
	char ch[2];
	for(int a,b,c,d,K;Q--;){
		scanf("%s%d%d",ch,&a,&b);
		if(ch[0] == 'R'){
			int t = add(l[a] - l[b] + mod);
			for(int j=0,p=t;j<=10;j++,p=1ll*p*b%mod)
				upd(tl[j],b,p);
			for(int j=0,p=mod-t;j<=10;j++,p=1ll*p*a%mod)
				upd(tl[j],a,p);
			swap(l[a],l[b]);
		}
		if(ch[0] == 'C'){
			int t = add(u[a] - u[b] + mod);
			for(int j=0,p=t;j<=10;j++,p=1ll*p*b%mod)
				upd(tu[j],b,p);
			for(int j=0,p=mod-t;j<=10;j++,p=1ll*p*a%mod)
				upd(tu[j],a,p);
			swap(u[a],u[b]);
		}
		if(ch[0] == 'Q'){
			scanf("%d%d%d",&c,&d,&K);
			swap(b,c);
			static int ar[11]={};
			int ans = 0 , sml = 0 , smr = 0;
			
			for(int j=0;j<=K;j++){
				ar[j] = add(qry(tl[j],b) - qry(tl[j],a-1) + mod);
				for(int k=0,p=1;k<=K;k++,p=1ll*p*b%mod) if(P[K][k][j])
					sml = (sml + 1ll * P[K][k][j] * ar[j] % mod * p) % mod;
			}
			
			ans = (ans + sml * 1ll * C(d-c+K+1,K+1)) % mod;
			
			for(int j=0;j<=K;j++){
				ar[j] = add(qry(tu[j],d) - qry(tu[j],c-1) + mod);
				for(int k=0,p=1;k<=K;k++,p=1ll*p*d%mod) if(P[K][k][j])
					smr = (smr + 1ll * P[K][k][j] * ar[j] % mod * p) % mod;
			}
			ans = (ans + smr * 1ll * C(b-a+K+1,K+1)) % mod;
			printf("%d\n",(ans+mod)%mod);
		}
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章