zoukankan      html  css  js  c++  java
  • BZOJ4403 序列统计—Lucas你好

      绝对是全网写的最详细的一篇题解(因为我弱) 

      题目:序列统计  代码难度:简单  思维难度:提高+—省选

      讲下题面:给定三个正整数N、L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量。输出答案对10^6+3取模的结果。

      。。。    防

      。。。    蒯

      。。。    神

      。。。    器

      好了,把我的做题思路说说。

      首先我们可以看出,L和R的具体值是没有卵用的,你只需要知道它们的差+1,记为m。同时T<=100也意味着各组询问之间应该并没有关系。

      然后我们会想到,这肯定不能一步出解(事实证明我被打脸了)。然后我们来找,对于条件(i,m),它的解是怎么来的。

      长度为i,备选数的值域(下面就叫做值数)有m个的单调不下降序列有多少个呢?

      这么一想不是很好想出来。那么我们想,如果把相同的数归入一个集合,或者叫抽屉,给它们以里面的数的代数值为编号,这个序列就可以看成一段段连续的抽屉,且它们的编号成递增。

      问题是不是可以抽象成:我有m个有编号的抽屉,要把i个相同的苹果放进去,问有多少种方法?

      此时问题已经渐渐清晰成具体模型了,但对于有些人(such as me)来说还是很玄学。于是我们再看看。

      上面那个问题下,抽屉是不动物体。现在我们把苹果当成不动物体看看:

      有i个苹果,要把它们分成至多m个区间,有多少种方法?

      这个时候千万不要想复杂了。对于这个问题,如果我们不局限于单个的i和m,而是把它们巧妙转化,整合在一起的话——

      有i个苹果,m-1个挡板。我们要在苹果中间插入挡板(也可以是最两侧),有多少种方法?

      换言之——

      有m+i-1个位子,你要在里面放m-1个挡板,有多少种放法?

      那么就是显然的组合数学!C(i+m-1,m-1)!

      那么我们知道(i,m)的答案就是C(i+m-1,m-1)。

      那么答案就是sigma(i from 1 to n)C(i+m-1,m-1);

      然而这是会T的复杂度。我们画出杨辉三角(或者根本不用画),就能发现它是在三角上的一条向左下倾斜的线。那么优化就顺(sang)理(xin)成(bing)章(kuang)了:

      在右上角加一个C(m,m),根据杨辉三角的特点,我们可以一路消掉,一直到C(N+M,M);

      因为我们之前加上了C(M,M),所以答案要减一。Ans=C(N+M,M)-1;正面肛Lucas定理。

      介绍一下Lucas定理:C(N,M)%P=Lucas(N,M,P)=C(N%P,M%P)*Lucas(N/P,M/P,P);

      逆元和阶乘预处理一下就好了。

      

    #include    <iostream>
    #include    <cstdio>
    #include    <cstdlib>
    #include    <algorithm>
    #include    <vector>
    #include    <cstring>
    #include    <queue>
    #define LL long long int
    #define ls (x << 1)
    #define rs (x << 1 | 1)
    #define MID int mid=(l+r)>>1
    using namespace std;
    const LL Mod = 1000003;
    LL cmod[Mod],A[Mod],J[Mod],n,m;
    LL gi()
    {
      LL x=0,res=1;char ch=getchar();
      while(ch>'9'||ch<'0'){if(ch=='-')res*=-1;ch=getchar();}
      while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
      return x*res;
    }
    LL C(LL N,LL M,LL P)
    {
      if(M>N)return 0ll;
      LL ans=J[N];
      ans=ans*A[J[N-M]]%P;
      ans=ans*A[J[M]]%P;
      return ans;
    }
    LL Lucas(LL N,LL M,LL P)
    {
      if(M==0)return 1ll;
      if(N<P&&M<P)return C(N,M,P);
      LL c=C(N%P,M%P,P);  if(!c)return 0ll;
      LL L=Lucas(N/P,M/P,P);return (c*L)%P;
    }
    int main()
    {
      int T=gi();J[0]=A[1]=J[1]=1;
      for(LL i=2;i<Mod;++i)A[i]=((Mod-Mod/i)*A[Mod%i])%Mod;
      for(LL i=2;i<Mod;++i)J[i]=(J[i-1]*i)%Mod;
      while(T--)
        {
          n=gi();m=(gi()-gi());m=-m+1;
          printf("%lld
    ",(Lucas(n+m,n,Mod)-1+Mod)%Mod);
        }
      return 0;
    }
    
    
  • 相关阅读:
    报错注入验证sqli
    pycharm out of memory 闪退
    集群、分布式、负载均衡区别与联系
    如何获取线程池ThreadPoolExecutor正在运行的线程
    docker快速安装mysql
    基于guava实现本地缓存
    NIO selector 多路复用reactor线程模型
    网络编程之NIO
    网络编程之BIO
    反射性能研究,反射赋值与set方法赋值对比
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/6592128.html
Copyright © 2011-2022 走看看