uoj#420. 【集训队作业2018】矩形(组合数学)

题面

传送门

题解

这辣鸡题目做了咱整整三天……咱果然还是太菜了……好珂怕的推倒啊……

首先把它变成

[left( sum_{i = 1}^{n} sum_{j = 1}^{m} F(i, j) \, h^{im + j} ight) mod p]

那么最后求答案的时候乘上的({1over h^{m+1}})就行了

我们考虑对(v)(即题目中的(f_i))和(c)分别计算贡献

(sub_1)

对于(v_x),打个表可以发现,第(x)行第(1)列它的系数为(b),第(2)列系数为(b^2),以及第(x+i)行第(j)列的系数为({i+j-1choose j-1}a^ib^jh^{(i+x)m}h^j)

我们对它的系数求和,就是

[egin{aligned} cnt &=sum_{i=0}^{n-x}a^ih^{(i+x)m}sum_{j=1}^{m}{i+j-1choose j-1}b^{j}h^{j}\ &=bh^{xm+1}sum_{i=0}^{n-x}a^ih^{im}sum_{j=0}^{m-1}{i+jchoose j}b^{j}h^{j}\ end{aligned} ]

[egin{aligned} f_n=sum_{i=0}^na^ih^{im}sum_{j=0}^{m-1}{i+jchoose j}b^{j}h^{j}\ g_n=sum_{j=0}^{m-1}{n+jchoose j}b^{j}h^{j}\ end{aligned} ]

于是我们显然可以写出(f_n)的递推式(f_n=f_{n-1}+a^nh^{nm}g_n)

那么我们只要能搞出(g)就可以求出(f),进而求出每个(v_x)的系数了

那么继续推倒

[egin{aligned} g_n &=sum_{j=0}^{m-1}{n+jchoose j}b^{j}h^{j}\ &=sum_{j=0}^{m-1}left({n+j-1choose j-1}+{n-1+jchoose j} ight)b^{j}h^{j}\ &=bhsum_{j=0}^{m-2}{n+jchoose j}b^{j}h^{j}+sum_{j=0}^{m-1}{n-1+jchoose j}b^{j}h^{j}\ &=bhleft(g_n-{n+m-1choose m-1}b^{m-1}h^{m-1} ight)+g_{n-1} end{aligned} ]

然后就分类讨论啊,如果(bh)等于(1),就消掉(g_n),可以直接得出(g_{n-1})的式子。如果(bh)不等于(1),就移项解方程。于是

[g_n=egin{cases} {n+mchoose m-1}&bh=1\ {g_{n-1}+{n+m-1choose m-1}b^mh^mover 1-bh}&bh eq 1 end{cases} ]

初值分别为(m(bh=1))({1-b^mh^mover 1-bh}(bh eq 1))

然后递推出(g),进而求出(f),对于每个(v_x)乘上(bh^{xm+1})(f_{n-x})就行了

(sub_2)

然后我们考虑(c)的贡献

对于位置((x,y))((i,j)(ileq x,jleq y))上的每一个(c)都会对这一个位置有贡献,我们可以看做向下走一步乘(a),向右走一步乘(b)((x,y))(c)的系数就是从所有((i,j))走到它的所有路径的权值之和。那么这个位置上(c)的系数就是就是

[F(x,y)=sum_{i=0}^{x-1}sum_{j=0}^{y-1}a^ib^j{i+jchoose j} ]

总的系数就是

[sum_{x=1}^nh^{xn}sum_{y=1}^mh^ysum_{i=0}^{x-1}sum_{j=0}^{y-1}a^ib^j{i+jchoose j} ]

我们记(G(x,y)=h^ysum_{i=0}^{x-1}sum_{j=0}^{y-1}a^ib^j{i+jchoose j})

和上面一样化简。

[egin{aligned} G(x,y) &=h^ysum_{i=0}^{x-1}sum_{j=0}^{y-1}a^ib^jleft({i+j-1choose j-1}+{i-1+jchoose j} ight)\ &=h^yasum_{i=0}^{x-2}sum_{j=0}^{y-1}a^ib^j{i+jchoose j}+h^ybsum_{i=0}^{x-1}sum_{j=0}^{y-2}a^ib^j{i+jchoose j}+h^y end{aligned} ]

注意,中间把组合数拆开来的时候,这个式子对({0choose 0})实际上是不适用的,所以我们少算了({0choose 0})的贡献,所以最后要加上(h^y)(咱因为没发现这个细节卡了好久)

继续推倒

[G(x,y)=aG(x-1,y)+bleft(G(x,y)-hsum_{i=0}^{x-1}a^ib^{y-1}h^{y-1}{i+y-1choose y-1} ight)+h^y ]

我们对这个东西求一个和,也就是记(T(x)=sum_{y=1}^m G(x,y)),有

[T(x)=aT(x-1)+bleft(T(x)-hsum_{i=0}^{x-1}a^isum_{j=0}^{m-1}b^jh^j{i+jchoose j} ight)+{h(1-h^m)over 1-h} ]

虽然最后的(h^y)的求和还要特判一下(h=1)的情况不过想必大家都是明白的我就不写了

中间那一大坨是什么东西啊……回过头去看看……

(sum_{j=0}^{m-1}b^jh^j{i+jchoose j})不等于(g_i)么……

[T(x)=aT(x-1)+bleft(T(x)-hsum_{i=0}^{x-1}a^ig_i ight)+{h(1-h^m)over 1-h} ]

还是分类讨论,如果(b=1)我们可以直接求出(T(x-1))的通项公式,否则就可以解出(T(x))的递推公式

然后枚举(x),每一个(x)都要让系数加上(h^{xm}T(x)),最后系数乘上(c)就行了

搞清楚字母哪个是哪个,别跟咱一样连自己写的啥都不知道了……

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
int read(){
    R int res,f=1;R char ch;
    while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    return res*f;
}
const int N=1e6+15;
int v[N],f[N],g[N],d[N],inv[N],t[N];
int n,m,h,P,a,b,c,res,x,y;
inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R ll y){
	R int res=1;
	for(;y;y>>=1,x=mul(x,x))if(y&1)res=mul(res,x);
	return res;
}
int calc1(){
	int res=0,tmp;
	if(mul(b,h)==1){
		f[0]=g[0]=tmp=m;
		fp(i,1,n){
			tmp=1ll*(i+m)%P*tmp%P*inv[i+1]%P;
			g[i]=tmp;
		}
	}else{
		int p=mul(b,h),q=ksm(p,m);
		p=ksm(dec(1,p),P-2);
		tmp=1,f[0]=g[0]=mul(dec(1,q),p);
		fp(i,1,n){
			tmp=1ll*(i+m-1)%P*tmp%P*inv[i]%P;
			g[i]=dec(g[i-1],mul(tmp,q)),g[i]=mul(g[i],p);
		}
	}
	int p=1,k=mul(a,ksm(h,m));
	fp(i,1,n)p=mul(p,k),f[i]=add(f[i-1],mul(p,g[i]));
	int x=mul(b,h),y=ksm(h,m);
	fp(i,1,n)x=mul(x,y),res=add(res,1ll*x*f[n-i]%P*v[i]%P);
	return res;
}
int calc2(){
	int res=0,qwq=(h==1)?m%P:1ll*h*dec(1,ksm(h,m))%P*ksm(dec(1,h),P-2)%P;
	if(b==1){
		int tmp=g[0],k=1,inva=ksm(a,P-2);
		fp(i,1,n)k=mul(k,a),tmp=add(tmp,mul(k,g[i])),t[i]=mul(dec(1ll*tmp*h%P*b%P,qwq),inva);
	}else{
		int tmp=g[0],k=1,invb=ksm(dec(1,b),P-2);
		fp(i,1,n){
			t[i]=mul(a,t[i-1]);
			t[i]=dec(t[i],1ll*b*h%P*tmp%P);
			t[i]=add(t[i],qwq);
			t[i]=mul(t[i],invb);
			k=mul(k,a),tmp=add(tmp,mul(k,g[i]));
		}
	}
	int g=1,k=ksm(h,m);
	fp(i,1,n)g=mul(g,k),res=add(res,mul(g,t[i]));
	return mul(res,c);
}
int main(){
//	freopen("testdata.in","r",stdin);
	read(),n=read(),m=read(),h=read(),P=read(),a=read(),b=read(),c=read();
	if(!h)return printf("%d
",add(c,mul(b,read()))),0;
	inv[0]=inv[1]=1;fp(i,2,n+5)inv[i]=mul(P-P/i,inv[P%i]);
	fp(i,1,n)v[i]=read();
	x=calc1(),y=calc2();
	res=ksm(h,m+1),res=ksm(res,P-2),res=mul(res,add(x,y));
	printf("%d
",res);
	return 0;
}
原文地址:https://www.cnblogs.com/bztMinamoto/p/10466783.html