zoukankan      html  css  js  c++  java
  • 点亮灯笼

    源代码:
    
    #include<cstdio>
    #include<algorithm>
    #define LL long long //这坑爹的数据逼我的!
    #define INF 1000000007
    using namespace std;
    LL n,m,Num(0),Sum(0),W[100001],f[100001],Prime[100001];
    bool Vis[100001]={0};
    struct Node
    {
        LL S,L;
    }i[100001];
    void Euler() //欧拉筛法。
    {
        for (LL a=2;a<=n;a++)
        {
            if (!Vis[a])
              Prime[++Sum]=a;
            for (LL b=1;b<=Sum&&Prime[b]*a<=n;b++)
            {
                Vis[Prime[b]*a]=true;
                if (!(a%Prime[b]))
                  break;
            }
        }
    }
    LL Count(LL X,LL T) //快速幂。
    {
        LL Ans=1;
        while (T)
        {
            if (T&1)
              Ans=(Ans*X)%INF;
            X=(X*X)%INF;
            T>>=1;
        }
        return Ans;
    }
    int main() //这个数论题你出得好,而且多了一些细节在里面,整惨了。
    {
        scanf("%d%d",&n,&m);
        Euler();
        for (LL a=1;a<=m;a++)
          scanf("%d",&W[a]);
        sort(W+1,W+m+1);
        if (W[1]>1) //头。
        {
            i[++Num].L=W[1]-1; //长度。
            i[Num].S=1; //方案数。
        }
        if (W[m]<n) //尾。
        {
            i[++Num].L=n-W[m];
            i[Num].S=1;
        }
        for (LL a=2;a<=m;a++) //区间预处理。
          if (W[a]-W[a-1]-1)
          {
            i[++Num].L=W[a]-W[a-1]-1;
            i[Num].S=Count(2,i[Num].L-1);
          }
        for (LL a=1;a<=Sum;a++) //阶乘分解质因数。
        {
            LL t=n-m;
            while (t)
            {
                f[a]+=t/Prime[a]; //这个处理就妙了,详见下。
                t/=Prime[a];
            }
        }
        for (LL a=1;a<=Num;a++)
          for (LL b=1;b<=Sum;b++)
          {
            LL t=i[a].L;
            while (t)
            {
                f[b]-=t/Prime[b];
                t/=Prime[b];
            }
          }
        LL Ans=1;
        for (LL a=1;a<=Sum;a++)
          for (LL b=1;b<=f[a];b++)
            Ans=(Ans*Prime[a])%INF; //最后统计。
        for (LL a=1;a<=Num;a++)
          Ans=(Ans*i[a].S)%INF;
        printf("%lld",Ans);
        return 0;
    }
    
    /*
        什么叫做神题,这***的就叫神题!
        分析问题,如样例3:□ □ □ √ □ □ □ √ □ □ □
        将已点燃的灯作为割点进行分段,会发现,单独的一段方案数为2^(Length-1)。
        那么怎样将其合并到一起呢?
        1 1 1 2 2 2 3 3 3,其中的数字表示这一次在第几段中取数,那么大的框架就形成了:
            (n-m)!/p1!p2!...pq!
        这个公式如此牛*,怎么来的呢?
        (n-m)!表示这些数总的全排列,仔细想一想,除以这些数就可以得到对于此区间数单一的方案总数。
        但这只是针对一种方案的排列总数,接下来再乘以每段的方案数即可。
        直接处理会导致溢出或错误,需要进行质因数分解,因为是阶乘,所以分解比较特别。
    当然,阶乘分解质因数也是一个噱头。
    对于n!=1*2*3*4*...*(n-2)*(n-1)*n,其中m的倍数有:m、2m、3m、...、n/m*m(共(n/m)个),则先加上(n/m)。
    处理之后,数列就变为了:1、2、3、...、n/m/m,其中m的倍数有:m、2m、3m、...、n/m/m*m(共(n/m/m)个),则再加上(n/m/m),以此类推,直到为空。
    */
  • 相关阅读:
    day 80 视图家族
    day 79 drf 多表关联操作
    day 78 drf 序列化
    day 77 drf中请求、渲染、解析、异常、响应模块的二次封装
    day 76 drf
    python小知识
    请求 渲染 解析 异常 响应模块
    子组件
    vue基础(2)
    vue基础
  • 原文地址:https://www.cnblogs.com/Ackermann/p/5992763.html
Copyright © 2011-2022 走看看