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;
}

剩餘的題也儘量補

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章