zoukankan      html  css  js  c++  java
  • P4345 [SHOI2015]超能粒子炮改

    题目描述

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

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

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

    数据范围: 对于 100% 的数据,\(t=100000\)\(n,k \le 10^{18}\).

    solution

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

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

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

    我们要求的是这个柿子

    \(\displaystyle\sum_{i=0}^{k}C_{n}^{i} \bmod 2333\)

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

    \(\displaystyle\sum_{i=0}^{k}C_{n/p}^{i/p}C_{n\bmod p}^{i\bmod p}\bmod p\)

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

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

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

    就是 \(\displaystyle\sum_{i=0}^{p-1}C_{n \bmod p}^{i} \times \displaystyle\sum_{i=0}^{k/p-1} C_{n/p}^{i}\)

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

    也就是 \(\displaystyle\sum_{i=0}^{k \bmod p}C_{n \bmod p}^{i}\times C_{n/p}^{k/p}\)

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

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

    总柿子

    \(\displaystyle\sum_{i=0}^{k}C_{n}^{i} \bmod 2333\)

    =\(\displaystyle\sum_{i=0}^{k}C_{n/p}^{i/p}C_{n\bmod p}^{i\bmod p}\bmod p\)

    =\(\displaystyle\sum_{i=0}^{p-1}C_{n \bmod p}^{i} \times \displaystyle\sum_{i=0}^{k/p-1} C_{n/p}^{i}\)+ \(\displaystyle\sum_{i=0}^{k \bmod p}C_{n \bmod p}^{i}\times C_{n/p}^{k/p}\)

    =\(f(n \bmod p,p-1) \times f(n \bmod p,k/p-1) + C_{n/p}^{k/p} \times f(n \bmod p,k \bmod p)\)

    其中 \(f(x,y)\) = \(\displaystyle\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\n",calc(a,b));
    	}
    	return 0;
    }
    

    ENDING

  • 相关阅读:
    java new 关键字到底做了什么?
    (转载)Eclipse中使用SVN
    图标常用网站
    正则表达式之RegExp对象
    表单验证之日期大小验证
    表单验证之正则表达式
    表单验证之JQuery Validate控件
    (转载)SVN使用说明
    oracle中group by 和order by同时存在时
    Oracle用户密码过期问题解决
  • 原文地址:https://www.cnblogs.com/genshy/p/13456251.html
Copyright © 2011-2022 走看看