zoukankan      html  css  js  c++  java
  • NOIP模拟34

    考试的时候被T2卡了一年。。。。考虑了一下正解的式子,然后没去给左边分解因数,去给后面乘倍数。。。理论复杂度O(n^2),实际好像卡不掉的样子。但是由于我智障的打了一棵主席树,他M了。。。。

    预计得分100+??+20,实际得分100+70+20

    T3,

      这道题dp式子想一想就出来了,但是由于模数不保证质数,如果用组合数要exlucas,其实可以不用组合数,但是由于我过于智障,还是打了组合数打法,但是由于我不会懒得打ex,于是我们可以。。。。。分解质因数。。。。。

      首先求出1到m每个数的质因子,然后对于组合数分解成质因数相乘的形式,如果每求一个组合数都暴力将所有质因子乘一遍的话,显然会死,考虑优化:

      从当前组合数递推到下一个质组合数只需要乘一个数,再除掉一个数,我们观察到除掉的那个数必然<5000,于是我们可以每次将小于5000的质因子暴力乘一遍,再乘上大于5000的质因子的乘积,那么复杂度就对了。

      注意在求每个数的质因子时,我们不需要每个数O(sqrt(n))求,可以在线筛的同时处理出来,具体来说,i×pri的质因子一定只比i多一个pri,我们可以记录每个数的前趋是谁,这样复杂度O(n),也可以直接让乘积继承i的vector,复杂度和埃氏筛一样,为O(nloglogn),都是可以接受的。

    代码比exlucas短,效率也快很多(虽然不如不用组合数)

     1 #include<bits/stdc++.h>
     2 #define ll long long
     3 using namespace std;
     4 int n,m,p,pri[1000005],tot,mx,a[1000005];
     5 vector<int>h[1000005];
     6 char v[1000005];
     7 ll num[5005][5005],f[2][5005],c[5005],aa=1,sum[1000005];
     8 inline int read(int x=0,char ch=getchar()){
     9     while(ch<'0'||ch>'9')ch=getchar();
    10     while(ch>='0'&&ch<='9')x=x*10-48+ch,ch=getchar();
    11     return x;
    12 }
    13 inline ll qpow(ll x,ll y,ll ans=1){
    14     for(;y;y>>=1,x=x*x%p)
    15         if(y&1)
    16             ans=ans*x%p;
    17     return ans;
    18 }
    19 signed main(){
    20     scanf("%d%d%d",&n,&m,&p);
    21     for(int i=1;i<=n;i++) a[i]=read(),mx=max(mx,a[i]);
    22     for(int i=2;i<=m;i++){
    23         if(!v[i]) pri[++tot]=i,h[i].push_back(i);
    24         for(int j=1;j<=tot&&i*pri[j]<=m;j++){
    25             v[i*pri[j]]=true;
    26             h[i*pri[j]]=h[i];
    27             h[i*pri[j]].push_back(pri[j]);
    28             if(i%pri[j]==0) break;
    29         }
    30     }
    31     for(int j=0;j<h[m].size();j++){
    32         if(h[m][j]>5000)aa=aa*h[m][j]%p;
    33         else sum[h[m][j]]++;
    34     }
    35     for(int i=1;i<=min(mx,m);i++){
    36         c[i]=aa;
    37         for(int j=1;j<=tot&&pri[j]<=5000;j++)
    38             c[i]=c[i]*qpow(pri[j],sum[pri[j]])%p;
    39         if(i!=min(mx,m)){
    40             for(int j=0;j<h[i+1].size();j++)
    41                 sum[h[i+1][j]]--;
    42             for(int j=0;j<h[m-i].size();j++)
    43                 if(h[m-i][j]>5000)aa=aa*h[m-i][j]%p;
    44                 else sum[h[m-i][j]]++;
    45         }
    46     }
    47     num[0][0]=1;
    48     for(int i=1;i<=mx;i++)
    49         for(int j=1;j<=min(mx,m);j++)
    50             num[i][j]=(num[i-1][j-1]*j+num[i-1][j]*(j-1))%p;
    51     for(int i=1;i<=min(a[1],m);i++)
    52         f[1][i]=num[a[1]][i]*c[i]%p,sum[1]=(sum[1]+f[1][i])%p;
    53     for(int i=2;i<=n;i++){
    54         sum[i]=0;
    55         for(int j=1;j<=min(a[i],m);j++){
    56             f[i&1][j]=((sum[i-1]*num[a[i]][j]%p*c[j]-(j<=a[i-1])*f[(i-1)&1][j]*num[a[i]][j])%p+p)%p;
    57             sum[i]=(sum[i]+f[i&1][j])%p;
    58         }
    59     }
    60     printf("%lld
    ",sum[n]);
    61     return 0;
    62 }
    View Code
  • 相关阅读:
    初探linux子系统集之led子系统(一)
    金融大数据分析从认知到实践(第1辑)(套装共3册)
    Blender权威指南
    零基础学Python
    中文版Photoshop CC图像处理与设计
    21天学通C++(第4版)
    Python应用开发实战
    电脑办公实战从入门到精通(超值版)
    Windows 10从新手到高手
    21天学通C语言(第7版)
  • 原文地址:https://www.cnblogs.com/hzoi-cbx/p/11447419.html
Copyright © 2011-2022 走看看