• bzoj1856


    这是一道无比涨姿势的题目

    首先总结一下这种输入几个数的题目,

    一般不是递推就是数学题

    显然,这道题用递推是无法做到O(n)的复杂度的

    那我们就考虑这是一道数学题了

    我已开始纠结在正向思维了,正向求好像确实不容易;

    某牛的报告点醒了我,我们设符合条件的序列为x,不符合的为y

    则x+y=c(n+m,n);

    现在我们只要求出y即可

    然后弱渣的我又卡住了,

    还是大牛的报告引用:我们不妨将0看做-1,那么对于一个不合法的序列,必然存在一个位置使得前缀和为-1,我们设这个最小的位置为k,即:a1+a2+……ak=-1,那么前缀和k-1为0,且ak=-1。接着,若我们将所有n+m个的这前k个数字取反,那么得到一个新的数列含有n+1个1和 m-1个-1,这个新的数列有C(n+m,n+1)种。不合法序列与新构造的这个序列是一一对应的关系。

    太神了。怎么想到的orz

    所以,ans=c(n+m,n)-c(n+m,n+1);

    因为n>m, 所以c(m+n,n)-c(n+m,n+1);

    (其实现在来看,这就是一个经典的卡特兰数的模型的变形)

    由于是组合还需要取模,就要涉及到除法取模;

    能回避除法取模的递推法(杨辉三角)复杂度肯定会TLE,

    然后我又涨姿势了,

    a/b ac (mod p);

    bc ≡1 (mod p) 我们把c叫做b的乘法逆元;

    一个数a除以另一个数b同余于a乘以b的乘法逆元模p

    怎么证呢?

    我们把乘法逆元的式子变换一下得 bc=pk+1 k∈Z

    则b=(pk+1)/c

    则a/b=a*c*(pk+1)≡ac (mod p)

    乘法逆元存在的充要条件是gcd(b,p)=1

    由于p=20100403>n+m,且是一个质数

    显然gcd(b,p)=1;

    那么怎么求乘法逆元呢?

    看到之前的变换式我们也不难想到,扩展欧几里得

    这道题唯一让我欣慰的地方就是,扩展欧几里得写对了……

     1 const mo=20100403;
     2 var ans:int64;
     3     n,m,i:longint;
     4 
     5 procedure exgcd(a,b:int64;var x,y:int64);
     6   var xx,yy:int64;
     7   begin
     8     if b=0 then
     9     begin
    10       x:=1;
    11       y:=0;
    12     end
    13     else begin
    14       exgcd(b,a mod b,x,y);
    15       xx:=x;
    16       yy:=y;
    17       x:=yy;
    18       y:=xx-a div b*yy;
    19     end;
    20   end;
    21 
    22 function re(a,p:int64):int64;
    23   var x,y:int64;
    24   begin
    25     exgcd(a,p,x,y);
    26     x:=(x+mo) mod mo;
    27     exit(x);
    28   end;
    29 
    30 function get(x:int64):int64;
    31   var i:int64;
    32   begin
    33     i:=1;
    34     get:=1;
    35     while i<x do
    36     begin
    37       inc(i);
    38       get:=get*i mod mo;
    39     end;
    40   end;
    41 
    42 function c(x,y:int64):int64;
    43   var a,b,d:int64;
    44   begin
    45     a:=get(x);
    46     b:=get(y);
    47     d:=get(x-y);
    48     c:=a*re(b,mo) mod mo*re(d,mo) mod mo;
    49   end;
    50 
    51 begin
    52   readln(n,m);
    53   ans:=c(n+m,n)-c(n+m,n+1);
    54   ans:=(ans+mo) mod mo;
    55   writeln(ans);
    56 end.
    View Code
  • 相关阅读:
    《程序员修炼之道》阅读笔记2
    《程序员修炼之道》阅读笔记1
    Ubuntu16桥接模式上网并设置静态ip
    读《架构漫谈》有感
    质量属性6个常见属性的场景分析
    sql注水
    python版本切换
    使用vue-cli构建 webpack打包工具时,生产环境下,每次build时,删除dist目录,并重新生成,以防dist目录文件越来越多。
    Java栈与堆
    从一个字符串s的第i个字符(不包括此字符)开始删除n个字符
  • 原文地址:https://www.cnblogs.com/phile/p/4473243.html
Copyright © 2020-2023  润新知