Codeforces Round #641(Div 2)

A. Orac and Factors
题目描述:For n≥2, we will denote as f(n) the smallest positive divisor of n, except 1.定义f(n) 为n的最小因子,除1以外。
Now, for two positive integers n and k, Orac asked you to add f(n) to n exactly k times (note that n will change after each operation, so f(n) may change too) and tell him the final value of n.
2.给定n和k,求n=n+f(n),一共k次。
分析:
随便分析几个数可得,n+f(n)会变成偶数。因此f(n)会变成2;
当n不为偶数时,需要运用唯一分解定理,即确定其最小质因子,f(n)+n就会变成偶数。后面每一次相当于加上2;

//AC代码;
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e6+55;
int prime[N];
bool p[N];
int cnt=0;
void deal()
{
    for(int i=2;i<N;++i){
        if(!p[i]){
            prime[cnt++]=i;
        }
        for(int j=0;j<cnt&&i*prime[j]<N;++j){
            p[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int t,n,k;
    ll ans;
    deal();
    scanf("%d",&t);
    while(t--){
        scanf("%d%d",&n,&k);
        if(n%2==0){
            ans=n+2*k;
        }else{
            int x;
            for(int i=0;i<cnt;++i){
                if(n%prime[i]==0){
                    x=prime[i];
                    break;
                }
            }
            ans=n+x+2*k-2;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

B. Orac and Models
题目描述:
There are n models in the shop numbered from 1 to n, with sizes s1,s2,…,sns1,s2,…,sn.
Orac thinks that the obtained arrangement is beatiful, if for any two adjacent models with indices ij and ij+1(note that ij<ij+1, because Orac arranged them properly), ij+1 is divisible by ij and sij<sij+1.
给定一个数组,求数组下标成倍数的最长上升序列。
分析:
对于任意一个数,他有几个因子,就可能有几个上升序列。例如:20:1,2,4,5,10,都是他的因子。 (1≤n≤100000),根据数据范围可以将每一个点记录其最长上升序列,即dp[i]表示i之前的是i的因子的最长上升序列。
现在我们就需要解决如何将一个数的因子全部分解出来。我用了枚举的方法
即1、2、3、、、sqrt(n)。

//状态方程	
   if(num[i]>num[k]) dp[i]=max(dp[i],dp[k]+1);
//AC代码;
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=1e5+55;
int num[N],dp[N];
int main()
{
    int t,n,k;
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",&num[i]);
            dp[i]=1;     //初始化dp[i]为1,每一个数本身都算一个;
        }
        for(int i=2;i<=n;++i){       
            int up=(int) sqrt(i);    //寻找所有因子;
            for(int j=1;j<=up;++j){
                if(i%j==0){
                    k=i/j;         //因子成对,即a*b=i,减少了时间复杂度,只需要找到sqrt(i);
                    if(num[i]>num[k]) dp[i]=max(dp[i],dp[k]+1);
                    if(num[i]>num[j]) dp[i]=max(dp[i],dp[j]+1);
                }
            }
        }
        int maxn=0;
        for(int i=1;i<=n;++i)
            maxn=max(maxn,dp[i]);
        printf("%d\n",maxn);
    }
    return 0;
}

C. Orac and LCM
题目描述:
一串数{s1,s2,s3…},求这串数字中每对数的最小公倍数的最小公因子。For example, gcd({8,12})=4, gcd({12,18,6})=6, gcd({8,12})=4, gcd({12,18,6})=6 and lcm({4,6})=12, lcm({4,6})=12.
分析:
对于每对数(a,b)最小公倍数来说,包含这两个数共有部分和每一个数的特有因子即: gcd(a,b)和a/gcd(a,b)、b/gcd(a,b);当n个数两两组合之后得到一组最小公倍数数集,再求这些数的最大公因子。相当于就是求这串数的共有部分相乘。由于是两两组合,所以只需要共有部分有n-1就行了。
例如:10 24 40 80 这4个数,分解开来就是 25、3222、5222、5222*2、5出现了3次,2出现了4次,4出现了3次,8出现了3次,但由于2、4可以属于8,因此因子就可以有5、8两个,也就是40;

//AC代码;
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=2e5+55;
int p[N],prime[N];
bool pp[N];
void deal()   //这儿用素数去分解它的因子,反正就是要找到所有公共因子
{
    int cnt=0;
    for(int i=2;i<N;++i){
        if(!pp[i]){
            prime[cnt++]=i;
        }
        for(int j=0;j<cnt&&prime[j]*i<N;++j){
            pp[prime[j]*i]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int n,x,y;
    deal();
    scanf("%d",&n);
    for(int i=0;i<n;++i){
        scanf("%d",&x);
        int j=0,k=0;
        while(x>1){
            while(x%prime[j]!=0){
                ++j;
                if(prime[j]*prime[j]>x) {
                    k=1;
                    break;
                }
            }
            if(k){
                p[x]++;
                break;
            }
            int cnt=1;
            while(x%prime[j]==0){
                cnt*=prime[j];
                p[cnt]++;   //每一个因子都要算进去,但后面以满足条件的最大因子为准。
                x/=prime[j];
            }
        }
    }
    n--;
    ll ans=1;
    for(int i=N-22;i>1;--i){  //从最后面开始遍历,大的将小的包含了。
        if(p[i]>=n&&ans%i!=0) ans*=i;
    }
    printf("%lld\n",ans);
    return 0;
}

剩余的题也尽量补

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值