• 2017.08.12【NOIP提高组】模拟赛B组 巴比伦


    ####Description/Input/Output
    这里写图片描述
    这里写图片描述
    ####Sample Input/Sample Output/Data Constraint
    这里写图片描述
    这里写图片描述

    题解:
    本题咋看上去是一道裸的DP呢??在认真看。发现DP不可做(db都知道)
    于是我们把题意简化一下:
    有n种宝具,其中有T种是神器且有限,bi表示第i个神器数量不超过bi件。
    若是相同的宝具数量相同,就是相同的搭配方案。求方案数 mod p。当然,选0件也是方案。
    然后我们不急于想本题,我们来看看另一个题目:

    有x个苹果,放进y个篮子中,但是篮子不一定每个都放。
    显然,方案数为C(y-1,x+y-1)=C(x,x+y-1)
    但是不限定放x个苹果的话,那么方案数为C(0,0+y-1)+C(1,1+y-1)+……+C(x,x+y-1)
    化简得:C(0,y-1)+C(1,y)+C(2,y+1)+……+C(x,x+y-1)
    根据一个神奇的公式C(n,m)=C(n-1,m-1)+C(n,m-1)
    然后上式就变成了C(x,x+y)

    算出这个之后,我们在回到原题,发现这样直接套上去是有问题的,为什么??因为题目中T个物品有限制,这个方案数里包含一些超标的(比如说一个物品有3个,选了4个即为超标)。那么我们考虑容斥原理。
    容斥原理是什么呢??
    例:
    一次期末考试,某班有15人数学得满分,有12人语文得满分,并且有4人语、数都是满分,那么这个班至少有一门得满分的同学有多少人?
    分析
    依题意,被计数的事物有语、数得满分两类,“数学得满分”称为“A类元素”,“语文得满分”称为“B类元素”,“语、数都是满分”称为“既是A类又是B类的元素”,“至少有一门得满分的同学”称为“A类和B类元素个数”的总和。
    答案
    15+12-4=23
    这是最简单的东东。
    我们来看个图更好理解:
    这里写图片描述
    求有颜色的面积
    于是面积为:
    红色球面积+黄色球面积+蓝色球面积-红色与黄色重叠-黄色与蓝色重叠-红色与蓝色重叠+红色与蓝色与黄色重叠。

    显而易见。
    T<=15,所以递归暴力枚举选哪些一定会超标。
    怎样保证一个物品一定超标?
    假设此物有xi个,至少选xi+1个才保证超标。
    所以暴力枚举一个物品是否超标,把xi+1加进sum里,最后超标的方案数为
    C(m-sum,n+m-sum)。解释:这就是已经选了sum个物品,剩下m-sum个物品,放进n个篮子里且不一定放完的方案数,而且一定合法。
    那么,本体就直接

    ans=原方案数-一个物品超标+两个超标-三个超标…

    但是我们会发现直接C来算会时间炸掉,而且用快速幂也会超。然后就引入一个特别厉害的公式:

    C(n,m) mod p=(C(n mod p,m mod p)*C(n div p,m div p)) mod p

    这样可以递归来求,当然有一些边界条件需要注意,你也可以预处理出阶乘与用快速幂。因为你求的时候可以用费马小定理。

    这道题就被完美地解出来了。

    Code:

    var
            i,j,k,l,n,m,t,q,p:longint;
            answer,ans,jl:int64;
            jc:array[0..100000] of longint;
            bh,a:array[0..20] of longint;
    function qsm(a,b,n:int64):int64;
    var
            t,y:int64;
    begin
            t:=1; y:=a;
            while b<>0 do
            begin
                    if(b and 1)=1 then t:=t*y mod n;
                    y:=y*y mod n;
                    b:=b shr 1;
            end;
            exit(t);
    end;
    function c(n,m:longint):longint;
    begin
            if (n<0)or(m<0) then exit(0)
            else if n=0 then exit(1)
            else if n>m then exit(0)
            else if n=m then exit(1)
            else
            if (n<=p)and(m<=p) then
            begin
                    exit(jc[m]*qsm(jc[m-n]*jc[n] mod p,p-2,p) mod p);
            end
            else
            exit(c(n mod p,m mod p)*c(n div p,m div p) mod p);
    end;
    procedure dg(dep,num,sum:longint);
    begin
            if dep>t then
            begin
                    bh[num]:=(bh[num]+c(m-sum,n+m-sum)) mod p;
            end
            else
            begin
                    dg(dep+1,num+1,sum+a[dep]+1);
                    dg(dep+1,num,sum);
            end;
    end;
    begin
            assign(input,'babylon.in');reset(input);
            assign(output,'babylon.out');rewrite(output);
            readln(n,t,m,p);
            jc[1]:=1;
            for i:=2 to p do
            begin
                    jc[i]:=(jc[i-1]*i) mod p;
            end;
            for i:=1 to t do
            begin
                    readln(a[i]);
            end;
            dg(1,0,0);
            ans:=c(m,n+m);
            for i:=1 to t do
            begin
                    if i mod 2=1 then
                    begin
                            ans:=(ans-bh[i]+p) mod p;
                    end
                    else
                    begin
                            ans:=(ans+bh[i]) mod p;
                    end;
            end;
            writeln(ans);
            close(input);close(output);
    end.
    
    
    
    我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
  • 相关阅读:
    ios 数据类型转换 UIImage转换为NSData NSData转换为NSString
    iOS UI 12 block传值
    iOS UI 11 单例
    iOS UI 08 uitableview 自定义cell
    iOS UI 07 uitableviewi3
    iOS UI 07 uitableviewi2
    iOS UI 07 uitableview
    iOS UI 05 传值
    iOS UI 04 轨道和动画
    iOS UI 03 事件和手势
  • 原文地址:https://www.cnblogs.com/RainbowCrown/p/11148427.html
Copyright © 2020-2023  润新知