【SHOI2015】超能粒子炮·改(Lucas定理)

我觉得这题挺难的,题解看来看去都是一步出结论,没什么过程,只有自己搞了。既然过了就尽量写清楚点。
这题的模数是个质数且比较小,需应用卢卡斯定理:

                                        C_n^m\ mod \ p=C_{n\ mod\ p}^{m\ mod\ p}*C_{n\div p}^{m\div p}\ mod\ p

现在用这个定理对题目所求一步一步地展开:

 

设答案(暂且不加上最外面的取模):

Sum[n][k] =C_n^0\ mod\ p+C_n^1\ mod\ p+...+C_n^k\ mod\ p

 

取模,用上Lucas定理:

=C_{n\ mod\ p}^{0\ mod\ p}*C_{n\div p}^{0\div p}+...+C_{n\ mod\ p}^{k\ mod\ p}*C_{n\div p}^{k\div p}  

 

把p=2333代入,方便起见,先把最外面的括号和mod p去掉

=C_{n\ mod\ 2333}^{0}*C_{n\div2333}^0+C_{n\ mod\ 2333}^{1}*C_{n\div 2333}^0+...+C_{n\ mod\ 2333}^{2332}*C_{n\div 2333}^0

+C_{n\ mod\ 2333}^0*C_{n\div 2333}^1+C_{n\ mod\ 2333}^1*C_{n\div 2333}^1+...+C_{n\ mod\ 2333}^{2332}*C_{n\div 2333}^1

+........

+C_{n\ mod\ 2333}^{0}*C_{n\div2333}^{k\div 2333}+C_{n\ mod\ 2333}^{1}*C_{n\div 2333}^{k\div 2333}+...+C_{n\ mod\ 2333}^{k\ mod\ p}*C_{n\div 2333}^{k\div 2333}

 

由于之前设Sum[i][j]=C_i^0+C_i^1+...+C_i^j,(暂时忽略取模)所以得到:

=Sum[n\ mod\ 2333][2332]*C_{n\div 2333}^0

+Sum[n\ mod\ 2333][2332]*C_{n\div 2333}^1

+........

+Sum[n\ mod\ 2333][k\ mod\ p]*C_{n\div 2333}^{k\div 2333}

 

除开最后一列,前面共有\frac{k}{2333}-1列,所以有:

=Sum[n\ mod\ 2333][2332]*Sum[n\div 2333][\frac{k}{2333}-1]

+Sum[n\ mod\ 2333][k\ mod\ p]*C_{n\div 2333}^{k\div 2333}

 

至此,结论就出来了。我们可以做一个预处理,算出Sum[i][j],C[i][j],(0<=i,j<2333)。由于Sum[n\div 2333][\frac{k}{2333}-1]里的数可能很大,无法预处理,只需递归地求出即可。至于大组合数,用卢卡斯定理。

最后,不要忘记取模。

#include<cstdio>
using namespace std;
typedef long long LL;
const LL p=2333;
LL N,K,T,sum[p+1][p+1],c[p+1][p+1];

void pre()
{
	int i,j;
	c[0][0]=1;
	for(i=1;i<p;i++)
	{
		c[i][0]=1;
		for(j=1;j<=i;j++)
			c[i][j]=(c[i-1][j]+c[i-1][j-1])%p;
	}
	
	sum[0][0]=1;
	for(i=1;i<p;i++)
	{
		sum[i][0]=1; sum[0][i]=1;
		for(j=1;j<p;j++)
			sum[i][j]=(sum[i][j-1]+c[i][j])%p;
	}
	
}

LL lucas(LL n,LL m)
{
	if(n<0||m<0) return 0;
	if(n<p&&m<p) return c[n][m];
	return lucas(n/p,m/p)*c[n%p][m%p]%p;
}

LL calc(LL n,LL k)
{
	if(k<0) return 0;
	return (calc(n/p,k/p-1)*sum[n%p][p-1]+lucas(n/p,k/p)*sum[n%p][k%p])%p;
}

int main()
{
	pre(); scanf("%d",&T);
	while(T--)
	{
		scanf("%lld%lld",&N,&K);
		printf("%lld\n",calc(N,K));
	}
	return 0;
}

 

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/82355152