P4345 [SHOI2015]超能粒子炮改

Posted genshy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P4345 [SHOI2015]超能粒子炮改相关的知识,希望对你有一定的参考价值。

题目描述

曾经发明了脑洞治疗仪与超能粒子炮的发明家 SHTSC 又公开了他的新发明:超能粒子炮?改——一种可以发射威力更加强大的粒子流的神秘装置。

超能粒子炮?改相比超能粒子炮,在威力上有了本质的提升。它有两个参数 n,k ,它会向每个编号为 0 到 k (包含两端)的位置i发射威力为 (C_{n}^{i} mod 2333)的粒子流。

现在 SHTSC 给出了他的超能粒子炮?改的参数,让你求出其发射的粒子流的威力之和除以 2333所得的余数。

输入格式

第一行一个整数 t表示数据组数。

之后 t 行,每行两个整数 n、k,含义如题面描述。

输出格式

t 行,每行一个整数,表示其粒子流的威力之和模 2333 的值。

输入输出样例

输入 #1

3
5 5
10 7
1145 14

输出 #1

32
968
763

说明/提示

对于 10% 的数据, t=1 , (n,k le 1000)
对于 30% 的数据, t=1 ,(n,k le 1000000)
对于 50% 的数据, t=1, (n le 10^{18},k le 1000)
对于 70% 的数据, t=100, (n,k le 10^{18})
对于 100% 的数据,t=100000 , (n,k le 10^{18}).

首先,这道题可以用卢卡斯加大力吸氧得到50分。

然后,无论怎么调都会TLE。

那么我们就要开始想正解。

我们要求的是这个柿子

(sum_{i=0}^{k}C_{n}^{i} mod 2333)

我们可以用Lucas定理换一下变成

(sum_{i=0}^{k}C_{n/p}^{i/p}C_{nmod p}^{imod p}mod p)

然后,我们就会神奇的发现,(C_{n}^{i mod p})重复计算了好多次

我们发现从0-p-1到p-2p-1.....他们中间都有一段连续的(sum_{i=0}^{p-1}C_{n}{i})

这样,我们就可以先计算这些段出现了多少次

就是 (sum_{i=0}^{p-1}C_{n}^{i} imes sum_{i=0}^{k/p-1} C_{n/p}^{i})

对于剩下的一些散块,我们直接可以套用卢卡斯定理来求。

也就是 (sum_{i=0}^{k mod p}C_{n mod p}^{i} imes C_{n/p}^{k/p})

对于这个(sum_{i=0}^{p-1}C_{n}^{i})柿子,我们可以通过预处理出[0,p-1]的组合数的前缀和搞出来。

(sum_{i=0}^{k/p-1} C_{n/p}^{i})这个柿子呢,我们就可以直接递归处理。

总柿子

(sum_{i=0}^{k}C_{n}^{i} mod 2333)

=(sum_{i=0}^{k}C_{n/p}^{i/p}C_{nmod p}^{imod p}mod p)

=(sum_{i=0}^{p-1}C_{n}^{i} imes sum_{i=0}^{k/p-1} C_{n/p}^{i})+ (sum_{i=0}^{k mod p}C_{n mod p}^{i} imes C_{n/p}^{k/p})

=(f(n mod p,p-1) imes f(n mod p,k/p-1) imes C_{n/p}^{k/p} imes f(n mod p,k mod p))

其中 (f(x,y)) = (sum_{i = 0}^{y}C_{x}^{i})

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define LL long long
const int p = 2333;
LL t,a,b,c[2550][2550],f[2550][2550];
inline LL read()
{
	LL s = 0, w = 1; char ch = getchar();
	while(ch < ‘0‘ || ch > ‘9‘){if(ch == ‘-‘) w = -1; ch = getchar();}
	while(ch >= ‘0‘ && ch <= ‘9‘){s = s * 10+ch -‘0‘; ch = getchar();}
	return s * w;
}
LL Lucas(LL n, LL m)//Lucas定理求组合数
{
	if(m == 0) return 1;
	if(n < m) return 0;
	return c[n%p][m%p] * Lucas(n/p,m/p) % p;
}
LL calc(LL n,LL k)
{
	if(k < 0) return 0;
	if(n == 0 || k == 0) return 1;
	if(n < p && k < p) return f[n][k];
	return (f[n%p][p-1] * calc(n/p,k/p-1) % p + Lucas(n/p,k/p) * f[n%p][k%p] % p) % p;//递归处理
}
void YYCH()//预处理出0-p的组合数
{
	c[0][0] = f[0][0] = 1;
	for(int i = 1; i <= 2500; i++)//杨辉三角求组合数
	{
		c[i][0] = c[i][i] = 1;
		for(int j = 0; j <= i; j++)
		{
			c[i][j] = (c[i-1][j-1] + c[i-1][j]) % p;
		}
	}	
	for(int i = 0; i <= 2500; i++) f[i][0] = 1;
	for(int i = 0; i <= 2500; i++)//组合数的前缀和
	{
		for(int j = 1; j <= 2500; j++)
		{
			f[i][j] = (f[i][j-1] + c[i][j]) % p;
		}
	}
}
int main()
{
	t = read(); YYCH();
	while(t--)
	{
		a = read(); b = read();
		printf("%lld
",calc(a,b));
	}
	return 0;
}

ENDING










以上是关于P4345 [SHOI2015]超能粒子炮改的主要内容,如果未能解决你的问题,请参考以下文章

P4345 [SHOI2015]超能粒子炮·改 Lucas

bzoj4591 / P4345 [SHOI2015]超能粒子炮·改

P4345 [SHOI2015]超能粒子炮·改

[SHOI2015]超能粒子炮·改

bzoj4591 [Shoi2015]超能粒子炮·改

Bzoj4591 [Shoi2015]超能粒子炮·改