zoukankan      html  css  js  c++  java
  • [luogu5616]恶魔之树

    记录$lcm$的质因子状态(包括大于$sqrt 300$的质因子),设$f[s]$表示质因子状态为$s$的$lcm$之和,转移枚举当前的数$k$,转移到$lcm(s,k)$即可,时间复杂度为$o(ncdot |stats|)$($|stats|$会非常大)

    优化1:对于一个$k$,有$2^{cnt}-1$种方案转移到$lcm(s,k)$($cnt$为$k$出现次数),而$k$最多300个,因此时间复杂度降为$o(300cdot |stats|)$

    优化2:对于一个$k$,我们只关心$k$所含有的质因子,也就是说设令$g[s]=sum_{sin s'}f[s']$(理解一下,$s$中仅表示2,3,5,7,11,13,17以及$k$中含有的大质数,$s'$表示全部状态,$sin s'$即在$s$考虑的质数与$s'$对应的质数状态相同),那么可以直接在$g$上转移

    答案即求$sum_{s}f[s]$,由于对于19即以上的质因子,同一个数$k$不可能同时存在2个/种,因此从小到大枚举质因子,再枚举含有该质因子的数,对于已经其余的质因子通过上述方式压缩即可,$|stats|$为17496,复杂度可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 305
     4 #define STA 17496
     5 #define ll long long
     6 struct ji{
     7     int a[11];
     8 }o;
     9 int n,x,mod,a[N],vis[N],mi[300005],w[STA],p[7]={2,3,5,7,11,13,17};
    10 ll ans,f[STA][2];
    11 void add(ll &x,int y){
    12     x=(x+y)%mod;
    13 }
    14 int hash(ji k){
    15     return k.a[6]+3*k.a[5]+9*k.a[4]+27*k.a[3]+81*k.a[2]+324*k.a[1]+1944*k.a[0];
    16 }
    17 ji inv_hash(int k){
    18     ji ans;
    19     ans.a[0]=k/1944;
    20     ans.a[1]=k%1944/324;
    21     ans.a[2]=k%324/81;
    22     ans.a[3]=k%81/27;
    23     ans.a[4]=k%27/9;
    24     ans.a[5]=k%9/3;
    25     ans.a[6]=k%3;
    26     return ans;
    27 }
    28 ji dec(ji x,ji y){
    29     ji ans;
    30     for(int i=0;i<7;i++)ans.a[i]=max(x.a[i]-y.a[i],0);
    31     return ans;
    32 }
    33 ji mx(ji x,ji y){
    34     ji ans;
    35     for(int i=0;i<7;i++)ans.a[i]=max(x.a[i],y.a[i]);
    36     return ans;
    37 }
    38 ji div(int k){
    39     ji ans;
    40     for(int i=0;i<7;i++){
    41         ans.a[i]=0;
    42         while (k%p[i]==0){
    43             k/=p[i];
    44             ans.a[i]++;
    45         }
    46     }
    47     return ans;
    48 }
    49 int main(){
    50     scanf("%d%d",&n,&mod);
    51     mi[0]=w[0]=1;
    52     for(int i=1;i<=n;i++)mi[i]=2LL*mi[i-1]%mod;
    53     for(int i=1;i<STA;i++){
    54         o=inv_hash(i);
    55         for(int j=0;j<7;j++)
    56             if (o.a[j]){
    57                 o.a[j]--;
    58                 w[i]=1LL*w[hash(o)]*p[j]%mod;
    59                 break;
    60             }
    61     }
    62     for(int i=1;i<=n;i++){
    63         scanf("%d",&x);
    64         a[x]++;
    65     }
    66     f[0][0]=1;
    67     for(int i=1;i<N-4;i++)
    68         if (w[hash(div(i))]==i){
    69             o=div(i);
    70             for(int j=STA-1;j>=0;j--)add(f[hash(mx(o,inv_hash(j)))][0],f[j][0]*(mi[a[i]]-1)%mod);
    71         }
    72     for(int i=0;i<STA;i++)f[i][0]=f[i][0]*w[i]%mod;
    73     for(int i=19;i<N-4;i++){
    74         if (w[hash(div(i))]>1)continue;
    75         for(int j=i;j<N-4;j+=i){
    76             o=div(j);
    77             for(int k=STA-1;k>=0;k--)
    78                 add(f[hash(mx(o,inv_hash(k)))][1],(i*f[k][0]+f[k][1])%mod*w[hash(dec(o,inv_hash(k)))]%mod*(mi[a[j]]-1)%mod);
    79         }
    80         for(int j=0;j<STA;j++){
    81             add(f[j][0],f[j][1]);
    82             f[j][1]=0;
    83         }
    84     }
    85     for(int i=0;i<STA;i++)add(ans,f[i][0]);
    86     printf("%d",ans);
    87 } 
    View Code
  • 相关阅读:
    【LeetCode-位运算】汉明距离总和
    python类的继承和重写
    单元测试unittest使用说明
    Java学习90
    Java学习89
    Java学习88
    Java学习87
    Java学习86
    Java学习85
    Java学习84
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13818614.html
Copyright © 2011-2022 走看看