• 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;
    }
    
    
  • 相关阅读:
    rest framework 认证 权限 频率
    rest framework 视图,路由
    rest framework 序列化
    10.3 Vue 路由系统
    10.4 Vue 父子传值
    10.2 Vue 环境安装
    10.1 ES6 的新增特性以及简单语法
    Django 跨域请求处理
    20190827 On Java8 第十四章 流式编程
    20190825 On Java8 第十三章 函数式编程
  • 原文地址:https://www.cnblogs.com/fenghaoran/p/6592128.html
Copyright © 2020-2023  润新知