Codeforces Round #713 (Div. 3)题解 F,G题

G. Short Task

题意:给出一个数字c,让你求最小的N,使得 ∑ d ∣ N = c \sum_{d|N}=c dN=c.

思路:首先,我们需要知道一个算术基本定理。

N = p 1 c 1 p 2 c 2 p 3 c 3 . . p k c k N={p_1}^{c_1}{p_2}^{c_2}{p_3}^{c_3}..{p_k}^{c_k} N=p1c1p2c2p3c3..pkck
∑ d ∣ N = ( 1 + p 1 + p 1 2 + . . . + p 1 c 1 ) ( 1 + p 2 + p 2 2 + . . . + p 2 c 2 ) . . . ( 1 + p k + p k 2 + . . . + p k c k ) \sum_{d|N}=(1+p_1+p_1^2+...+p_1^{c_1})(1+p_2+p_2^2+...+p_2^{c_2})...(1+p_k+p_k^2+...+p_k^{c_k}) dN=(1+p1+p12+...+p1c1)(1+p2+p22+...+p2c2)...(1+pk+pk2+...+pkck)

那么,我们用一个数组sum表示每个数的因数的和。对于N<1e7,我们可以先晒出1- 1 e 7 \sqrt{1e7} 1e7 内的所有的素数,对于 1 e 7 \sqrt{1e7} 1e7 到1e7之间的所有素数,我们直接sum[i]=i+1即可。我们首先找到每个数对应的最小质数。然后就可以利用上述公式进行计算。最后,我们倒序枚举出现的这个数的最小的位置即可。


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=1e7+10;
ll qk(ll a,ll b,ll p){
    if(b==0) return 1;
    if(b&1)  return a*qk(a,b-1,p)%p;
    else{
        ll mul=qk(a,b/2,p);
        return mul*mul%p;
    }
}
int d[N];
int ans[N];
int pnum=0;
ll sum[N];
int main(){
    freopen("test.in","r",stdin);
    int tmp=sqrt(N);
    for(int i=2;i<tmp;i++){   //找出1-N的每个数的最小质因数
        if(d[i]==0){
            d[i]=i;
            for(int j=i*i;j<N;j+=i){
                if(d[j]==0){
                    d[j]=i;
                }
            }
        }
    }
    sum[1]=1;
    for(int i=2;i<N;i++){
        if(d[i]==0){  //sqrt(N)之后的素数
            d[i]=i;
            sum[i]=i+1;
        }else{   
            int j=i;
            sum[i]=1;
            //算术基本定理求因数之后
            while(j%d[i]==0){
                j/=d[i];
                sum[i]=sum[i]*d[i]+1;
            }
            sum[i]=sum[i]*sum[j];
        }
    }
    //倒序枚举即可
    for(int i=N-1;i;i--){
        if(sum[i]<N){
            ans[sum[i]]=i;
        }
    }
    int t;
    cin>>t;
    while(t--){
        int c;
        cin>>c;
        if(ans[c]) cout<<ans[c]<<endl;
        else puts("-1");
    }
    fclose(stdout);
    return 0;
}

F. Education

题意:有n个位置,在每个位置每天有一个收益a[i],位置越靠近后面收益越高。同时每个位置有一个到达该位置所需要的花费,从第2个位置开始,到达该位置需要花费一定的费用b[i]。某人最开始在位置1,拥有的金钱为0,它可以待在当前位置,同时也可以通过一定的花费到达下一个位置,但只能一级一级到达。他想获得收益c的所需要的最少的天数。

思路:贪心,很显然。题目规定,越往后面收益值越高,那么我们就尽量到后面收益高的位置。所以,对于每一个位置,有两条路,一条路是我们可以计算假如待在这个位置直到获得收益c的天数。另一条路是我们也要继续往后面走,方便我们计算下一个位置的情况。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int N=120;
ll qk(ll a,ll b,ll p){
    if(b==0) return 1;
    if(b&1)  return a*qk(a,b-1,p)%p;
    else{
        ll mul=qk(a,b/2,p);
        return mul*mul%p;
    }
}
ll a[200010],b[200010],sum[100010];
void solve(){
    ll n,c;
    cin>>n>>c;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    for(int i=1;i<n;i++){
        cin>>b[i];
    }
    b[n]=0;
    ll ans=1e18;
    ll sum=0;  //目前拥有的钱
    ll res=0;   //当前花费了多少天
    for(int i=1;i<=n;i++){
        ans=min(ans,res+max(0ll,c-sum+a[i]-1)/a[i]);
        ll need=max(0ll,b[i]-sum+a[i]-1)/a[i];
        res+=need+1;
        sum+=a[i]*need-b[i];
    }
    cout<<ans<<endl;
}
int main(){
    //freopen("test.in","r",stdin);
    int t;
    cin>>t;
    while(t--){
        solve();
    }
    fclose(stdout);
    return 0;
}

这里,我介绍一个比较巧妙的一个地方,我们发现代码中有max(0ll,c-sum+a[i]-1)/a[i]这种的,其实这是为了我们计算所需要的天数。我们这个题目要求的是向上取整,而我们的C++默认的是向下取整(其实是有向上取整的函数)。然后题目是先减去(a[i]-1),然后后面直接加上1就行了,就不用担心除不尽的情况了。这只是一个小技巧,稍微提醒一下。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值