[数学杂题] LibreOJ #530「LibreOJ β Round #5」最小倍数

来源:互联网 发布:淘宝首页怎么加载数据 编辑:程序博客网 时间:2024/05/21 00:20

首先显然每个质数是独立的,对于 m 个 都算一次n的下界,最后取max
对于一个质数,算满足它至少出现e次的最小值,可以很暴力的二分,这样要两个 logO(Tmlog2V) 再卡卡常是能过的。但还有更好的解法,可以直接贪心算每次的下界:
考虑把 n 转成 p 进制,若权为 pi 的位上是v, 则这位对答案的贡献是 vi1j=0pj
然后就贪心的从高位到低位填即可,每次填保证之后合法的最小值。
这样就是 O(TmlogV)

#include<cstdio>#include<cmath>#include<algorithm>using namespace std;typedef long long LL;const int maxn=555;int N=550,n,m,b[maxn],p[maxn];LL ans,a[maxn];bool vis[maxn];void Pre(){    for(int i=2;i<=N;i++){        if(!vis[i]) p[++p[0]]=i;        for(int j=1;j<=p[0]&&(LL)i*p[j]<=N;j++){            vis[i*p[j]]=true;            if(i%p[j]==0) break;        }    }}LL pw[maxn],w[maxn],sum_w[maxn];LL Solve(int prm,LL m){     LL res=0; int _max;    w[1]=sum_w[1]=_max=1; pw[0]=1; pw[1]=prm;    for(int i=2;i<=70;i++){        pw[i]=pw[i-1]*prm;        w[i]=w[i-1]+pw[i-1], sum_w[i]=sum_w[i-1]+w[i], _max=i;        if(sum_w[i]*(prm-1)>m) break;    }    for(int i=_max;i>=1;i--){        if(sum_w[i-1]*(prm-1)>=m) continue;        int now=(m-sum_w[i-1]*(prm-1)+w[i]-1)/w[i];        res+=pw[i]*now;  m-=now*w[i];    }    return res;}int _test;int main(){    freopen("loj530.in","r",stdin);    freopen("loj530.out","w",stdout);    Pre();    scanf("%d",&_test);    while(_test--){        scanf("%d",&m);        for(int i=1;i<=m;i++) scanf("%lld",&a[i]);        ans=1;        for(int i=1;i<=m;i++) ans=max(ans,Solve(p[i],a[i]));        printf("%lld\n",ans);    }    return 0;}
原创粉丝点击