• [bzoj4591][Shoi2015][超能粒子炮·改] (lucas定理+组合计数)


    Description

    曾经发明了脑洞治疗仪&超能粒子炮的发明家SHTSC又公开了他的新发明:超能粒子炮·改--一种可以发射威力更加
    强大的粒子流的神秘装置。超能粒子炮·改相比超能粒子炮,在威力上有了本质的提升。它有三个参数n,k。它会
    向编号为0到k的位置发射威力为C(n,k) mod 2333的粒子流。现在SHTSC给出了他的超能粒子炮·改的参数,让你求
    其发射的粒子流的威力之和模2333。

    Input

    第一行一个整数t。表示数据组数。
    之后t行,每行二个整数n,k。含义如题面描述。
    k<=n<=10^18,t<=10^5

    Output

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

    Sample Input

    1
    5 5

    Sample Output

    32

    Solution

    易得,

    原式=C(n/2333,0)C(nmod2333,0)+C(n/2333,0)C(nmod2333,1)+...+C(n/2333,k/2333)C(nmod2333,kmod2333)   mod 2333

    也就是将原式中的各个mod 2333项拆分成两项再总体mod 2333

    同类项合并,分两种部分考虑:
    设k=k1*2333+k2 (0≤k1,k2)
    1)对于k1部分
    先考虑k1=0的情况,可以得出这些乘积的各个首项是C(n/2333,0),将其提出得到C(n/2333,0)*∑C(n%2333,i)(其中i∈[0,2333])
    考虑k1=1的情况,可得C(n/2333,1)*∑C(n%2333,i)(其中i∈[0,2333])
    考虑k1=2的情况,可得C(n/2333,2)*∑C(n%2333,i)(其中i∈[0,2333])
    ···  ···  ···  ···  ···  ···
    提公因式→→→∑C(n/2333,j)*∑C(n%2333,i)(其中i∈[0,2333],j∈[0,k1))
    重复3遍
    ∑C(n/2333,j)*∑C(n%2333,i)(其中i∈[0,2333],j∈[0,k1))
    ∑C(n/2333,j)*∑C(n%2333,i)(其中i∈[0,2333],j∈[0,k1))
    ∑C(n/2333,j)*∑C(n%2333,i)(其中i∈[0,2333],j∈[0,k1))
    吼,各位就等了,看看k2部分吧
    2)对于k2部分
    原式=C(n/2333,k1)*C(n%2333,0)+C(n/2333,k1)*C(n%2333,1)+······+C(n/2333,k1)*C(n%2333,k%2333)
    =C(n/2333,k1)*(∑C(n%2333,i))(其中i∈[0,k%2333])
    综上,ans=∑C(n/2333,j)*∑C(n%2333,i)(其中i∈[0,2333],j∈[0,k1))+C(n/2333,k1)*(∑C(n%2333,i))(其中i∈[0,k%2333])
     
    说了这么多,那么这个定理的用法是什么?
    显然是递归求解组合数的模数咯~
     

    所以对于这道题,我们先预处理出一个S(n,k)=∑C(n,i) (i∈[0,k]) (当然最后都是mod p意义下的),ans=S(n%2333,2332)*(∑C(n/2333,j)) (j∈[0,k1)) + C(n/2333,k1)*S(n%2333,k%2333)

    ans中的S()一定可以用二维的东西在规定时空内求出,而∑C(n/2333,j)就是我们超能粒子炮`改的子问题,递归求解即可,另,C(n/2333,k1)也可以用lucas定理递归来解

    于是这道题就口头ac了。

    00:30完成!

    #include <stdio.h>
    #include <string.h>
    #define md 2333
    #define LL long long
    inline LL Rin() {
      LL x=0,c=getchar();
      for(;c<48||c>57;c=getchar());
      for(;c>47&&c<58;c=getchar())
        x=x*10+c-(LL)48;
      return x; }
    inline LL mod(LL x) {
      return x-(x/md)*md; }
    LL frac[md+10],c[md+10][md+10],s[md+10][md+10];
    void calc() {
      frac[0]=1LL;
      for(int i=1;i<=md;i++)
        frac[i]=mod(frac[i-1]*(LL)i);
      c[0][0]=1LL;
      for(int i=1;i<=md;i++) {
        c[i][0]=c[i][i]=1LL;
        for(int j=1;j<i;j++)
          c[i][j]=mod(c[i-1][j-1]+c[i-1][j]); }
      for(int i=0;i<=md;i++) {
        s[i][0]=1LL;
        for(int j=1;j<=md;j++)
          s[i][j]=mod(s[i][j-1]+c[i][j]); } }
    LL lucas(LL n,LL k) {
      return k!=0LL?mod(c[n%md][k%md]*lucas(n/md,k/md)):1LL; }
    LL getans(LL n,LL k) {
      return k<0LL?0LL:mod(mod(s[mod(n)][md-1]*getans(n/md,k/md-1))+mod(lucas(n/md,k/md)*s[mod(n)][mod(k)])); }
    int main() {
      calc();
      LL n,k,T=Rin();
      while(T--)
        n=Rin(),k=Rin(),printf("%lld
    ",getans(n,k));
      return 0; }
  • 相关阅读:
    第五周读书笔记
    第五周课后作业(浅谈腾讯的创新)
    对象数组按属性排序
    id,pid数组转拓扑树结构
    ES6数组reduce()方法详解及高级技巧
    vue实现打印功能
    Js es6中扩展运算符(...)
    Axios 各种请求方式传递参数格式
    vue项目全局使用axios
    安装vue-cli脚手架
  • 原文地址:https://www.cnblogs.com/keshuqi/p/6275791.html
Copyright © 2020-2023  润新知