zoukankan      html  css  js  c++  java
  • CF300E. Empire Strikes Back

    题目链接(是的我越来越懒了。。)

    题目大意及数据范围:

    数据范围很大。“最小”二字让我们考虑二分,但是上界...不会爆long long让你写高精吧?

    我们可以发现,∑ai一定满足条件,所以上界是1e13。为什么满足呢?因为C(n+m,n)是整数,所以n!| ( (n+m)!/m! ) ,所以满足。

    然后问题只剩下怎么满足判断整除了。数很大,肯定要分解。n!的分解容易解决,因为我们只需考虑1e7范围内的质数即可,每次计算效率约为1e7/ln,总的复杂度能接受。所以只需解决各ai!如何分解。显然不能像n那个挨个质数地试,冗余过多,我们得考虑把各ai和在一起。既然都是阶乘,我们只需考虑每个数x对几个ai产生贡献即可(满足x≤ai的ai有几个),挨个将x分解的复杂度我们还是可以接受的(毕竟CF的机子,还开5s)。

    总时间复杂度O(alog(max{ai}) )

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i,l,r) for(int i=l;i<=r;++i)
    #define per(i,r,l) for(int i=r;i>=l;--i)
    
    typedef long long ll;
    
    const int N=1e6+3,V=1e7;
    
    int n,a[N];
    ll ans[V+3];//ans[j]
    
    namespace Euler{
        bool h[V+3];
        int pr[N],len,miz[V+3];//miz[x]=no
    
        void sieve(){
            rep(i,2,V){
                if(!h[i]){
                    pr[++len]=i;
                    miz[i]=len;
                }
                int val;
                for(int j=1;j<=len&&(val=pr[j]*i)<=V;++j){
                    h[val]=1;
                    miz[val]=j;
                    if(i%pr[j]==0) break;
                }
            }
            
        }
    
        void dvd(int x,int ct){//divide x to ans  ans[no]
            if(x==1) return ;
            int no=miz[x],P=pr[no];
            while(x%P==0){
                ans[no]+=ct;
                x/=P;
            }
            dvd(x,ct);
        }
    
        void calc(){
            int L=1;
            rep(i,2,V){
                while(a[L]<i&&L<=n) ++L;
                //ct=n-L+1
                dvd(i,n-L+1);
            }
        }
    
        bool ck(ll val){
            rep(j,1,len){
                ll sum=pr[j],P=pr[j],ad=0;
                while(sum<=val){
                    ad+=(val/sum);
                    sum*=P;
                }
                if(ad<ans[j]) return 0;
            }
            return 1;
        }
    
    }
    using Euler::sieve;
    using Euler::calc;
    using Euler::ck;
    
    
    int main(){
    
        sieve();
    
        scanf("%d",&n);
        rep(i,1,n) scanf("%d",&a[i]);
        sort(a+1,a+1+n);
    
        calc();
    
        ll L=1,R=1e13;
        while(L<R){
            ll mid=(L+R)>>1;
            if(ck(mid)) R=mid;
            else L=mid+1;
        }
    
        printf("%lld
    ",L);
    
    
        return 0;
    }
  • 相关阅读:
    Spring@Profile注解
    day 32 子进程的开启 及其用法
    day 31 udp 协议SOCK_DGRAM
    day 30 客户端获取cmd 命令的步骤
    day 29 socket 理论
    day 29 socket 初级版
    有关 组合 继承
    day 27 多态 接口 类方法 静态方法 hashlib 摘要算法模块
    新式类和经典类的区别
    day 28 hasattr getattr serattr delattr 和带__内置__ 类的内置方法
  • 原文地址:https://www.cnblogs.com/BLeaves/p/10432806.html
Copyright © 2011-2022 走看看