zoukankan      html  css  js  c++  java
  • [nowcoder5666B]Infinite Tree

    首先考虑由$1!,2!,...,n!$所构成的虚树的一些性质:
    1.每一个子树内所包含的阶乘的节点都是一个连续的区间(证明:对于子树k,如果存在$x!$和$y!$,即说明$x!$和$y!$的前$delta(1,k)$大质因子相同,那么$zin [x,y]$一定有$x! | z!|y!$,所以z!的前$delta(1,k)$大个质因子也因该相同,即z!在k子树内);
    2.记第i个点对应区间为$[l_{i}!,r_{i}!]$,设k的所有儿子$kcdot p_{i}$(不妨设$p1<p2<...<p_{son}$),对于$x!$和$y!$($x<y$),其所在子树为$kcdot maxdiv(x!/k)$和$kcdot maxdiv(y!/k)$($maxdiv$为最大质因数),由于$x!|y!$,因此$maxdiv(x!/k)le maxdiv(y!/k)$
    将答案从1开始调整(不断向下走),并维护对应区间$[l!,r!]$,那么修改量$Delta=sum w_{i}-sum_{i=l}^{r}w_{i}$,对于每一次移动,都需要保证新的$[l!,r!]$所对应的$Delta>0$(容易发现能满足这个的最多只有1个),然后令$ans-=Delta$
    考虑如何维护$[l!,r!]$,由于质因子单调不上升,所以从大到小枚举质因子p,分为两类(设该节点为k):1.可以走下去,那么令$l=min_{maxdiv(i!/k)=p}i$;2.不可以走下去,令$r=min_{maxdiv(i!/k)=p}i-1$并减小p(同时还要维护$Delta$)
    考虑如何求$min_{maxdiv(i!/k)=p}i$,相当于要保证$i!$中p的幂次不小于$k$中p的幂次中最小的i,那么将每一个数按p的幂次为次数放入p的vector中,然后$i!$中p的幂次即vector中不大于i的数个数,由于p的幂次每一次最多+1,因此不断往后取即可
    由于每一次操作要么减少素数大小,要么增加当前节点的深度,因此复杂度为$o(树高+素数个数)=o(nlog_{2}n+frac{n}{ln n})$
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 vector<int>v[N];
     5 int n,vis[N],sum[N],le[N],ri[N];
     6 long long s,ss,ans,a[N];
     7 int main(){
     8     for(int i=2;i<N-4;i++)
     9         if (!vis[i]){
    10             sum[i]=1;
    11             v[i].push_back(i);
    12             for(int j=2;i*j<N-4;j++){
    13                 vis[i*j]=1;
    14                 for(int k=j;k%i==0;k/=i){
    15                     sum[i*j]++;
    16                     v[i].push_back(i*j);
    17                 }
    18             }
    19         }
    20     for(int i=2;i<N-4;i++)sum[i]+=sum[i-1];
    21     while (scanf("%d",&n)!=EOF){
    22         s=ans=0;
    23         for(int i=1;i<=n;i++){
    24             scanf("%lld",&a[i]);
    25             s+=a[i];
    26             ans+=a[i]*sum[i];
    27             a[i]+=a[i-1];
    28         }
    29         int l=1,r=ri[n]=n,las=-1;
    30         for(int i=n;i>=2;i--){
    31             if (vis[i])continue;
    32             le[i]=upper_bound(v[i].begin(),v[i].end(),l)-v[i].begin();
    33             ans-=s*le[i]-1;
    34             if (las>=0)ri[i]=v[las][le[las]]-1;
    35             las=i;
    36             while (1){
    37                 ss=2*(a[r]-a[l-1])-2*(a[ri[i]]-a[v[i][le[i]]-1]); 
    38                 if (s-ss<=0)break;
    39                 s-=ss;
    40                 l=v[i][++le[i]];
    41                 r=ri[i];
    42                 ans-=s;
    43             }
    44             if (s<=0)break;
    45         }
    46         printf("%lld
    ",ans);
    47     }
    48 }
    View Code
  • 相关阅读:
    centos 7 nginx 安装
    搭建Nuget.Server push时,"Failed to process request. 'Method Not Allowed'"
    Failed to create prime the NuGet cache
    Centos 7 安装 Visual stdio Code
    diskpart 格式化u盘 制作u盘启动盘方法
    sql server 2012 数据库日志文件过大,怎么缩小?
    浏览器同源政策及其规避方法
    redis底层数据结构--简单动态字符串 链表 字典 跳跃表 整数集合 压缩列表
    php的闭包
    hash一致性算法
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/13308231.html
Copyright © 2011-2022 走看看