【简单计数知识2】JZOJ6405. 【NOIP2019模拟11.04】c

Description

【简单计数知识2】JZOJ6405. 【NOIP2019模拟11.04】c_第1张图片
【简单计数知识2】JZOJ6405. 【NOIP2019模拟11.04】c_第2张图片
n < = 1 e 6 , m < 1 e 9 + 7 n<=1e6,m<1e9+7 n<=1e6,m<1e9+7

Solution

  • 刚开始看到矩阵求逆后发现连裸的矩阵求逆我都不会(其实我去年应该是学过的。。。),只会一发n6的暴力对n2个点进行高斯消元。
  • 实际上,矩阵求逆有一种很好做的n3高斯消元。
  • 对于矩阵 A A A,将它变为单元矩阵 I I I,同时根据 A A A的操作,同步地操作一个 I I I,因为矩阵的操作是互逆的,所以 I I I在经过相同的操作后就变成了 A − A^- A
  • 考虑对于这个Pascal矩阵做同样的操作。
  • 注意到这个矩阵已经是一个三角形了,并且对于同一列,它们的分母都是一样的 j m j^m jm,所以在消元的时候可以忽略这个。那么只需要将这个矩阵消成一个对角线的1就好了。
  • 然后因为这个矩阵 P ( i , j ) = [ i > = j ] C i j P(i,j)=[i>=j]C_i^j P(i,j)=[i>=j]Cij,这个其实是二项式反演的基本式子,它的逆矩阵就是二项式反演的容斥系数 P ( i , j ) = [ i > = j ] ( − 1 ) i + j C i j P(i,j)=[i>=j](-1)^{i+j}C_i^j P(i,j)=[i>=j](1)i+jCij.
  • 然后再把 j m j^m jm乘上去就好了。
  • 最后计算每一列的平方和。即 ∑ i = 0 n ( C n i ) 2 \sum_{i=0}^n (C_n^i)^2 i=0n(Cni)2
  • 结论 ∑ i = 0 n ( C n i ) 2 = C 2 n n \sum_{i=0}^n (C_n^i)^2=C_{2n}^n i=0n(Cni)2=C2nn

小证明

  • 简单的理解成 C n i ∗ C n n − i C_n^i*C_n^{n-i} CniCnni即将2n个数分成两半,前一半选i个,后一半选n-i个,因为枚举了i,所以相当于是2n里面选n个。
#include
#include
#include
#include
#define maxm 2000005
#define ll long long 
#define mo 1000000007
using namespace std;

int n,m,i,j,k;
ll fct[maxm],ift[maxm],ans;

ll ksm(ll x,ll y){
	ll s=1;
	for(;y;y/=2,x=x*x%mo) if (y&1)
		s=s*x%mo;
	return s;
}

ll C(int n,int m){return fct[n]*ift[m]%mo*ift[n-m]%mo;}

int main(){
	freopen("c.in","r",stdin);
	freopen("c.out","w",stdout);
	scanf("%d%d",&n,&m);
	fct[0]=fct[1]=1;for(i=2;i<maxm;i++) fct[i]=fct[i-1]*i%mo;
	ift[maxm-1]=ksm(fct[maxm-1],mo-2);
	for(i=maxm-2;i>=0;i--) ift[i]=ift[i+1]*(i+1)%mo;
	for(i=1;i<=n;i++) ans+=ksm(i,2*m)*(C(2*i,i)-1)%mo;
	printf("%lld",ans%mo);
}

你可能感兴趣的:(题解,数论,计数)