Codeforces Round #641 (Div. 2) A~D题解

这场是打的真不好,写一下题解总结一下自己叭。

比赛链接:https://codeforces.ml/contest/1350

放一下队友链接:

核心选手:https://me.csdn.net/qq_43559193

核心选手:https://me.csdn.net/weixin_43916298

目录

Codeforces Round #641 (Div. 2) 

A. Orac and Factors

Code:

B. Orac and Models

Code:

C. Orac and LCM

Code:

D. Orac and Medians

Code:

Just Another Code:


Codeforces Round #641 (Div. 2) 

A. Orac and Factors

先开的B,A就没细看。

题意:

定义f(x)操作为x的最小的因子(除1以外),对x进行嵌套f函数,问嵌套k次之后的结果

题目思路:

水了:

若C=A*B ,那么C+A=A+A*B=A*(B+1),此时的最小的因子,是A,B最小的因子+1,所以只能为2

所以只需要求一个因子 ,其余+2*(m-1)即可

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include 
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll dp[maxn];
int main()
{
    int T;scanf("%d",&T);
    while(T--){
        read(n);read(m);
        ll ans=0;
        for(int i=2;i<=n;i++){
            if(n%i==0){
                ans=i;
                break;
            }
        }
        n+=ans;
        n+=(m-1)*2;
        printf("%lld\n",n);
    }
    return 0;
}

B. Orac and Models

题目大意:

求一个下标单调递增且互为倍数,且满足若i>j,则si>sj的最长子序列

题目思路:

先做的B ,都卡了十分钟,服..

原因在哪呢?题意读错了,题意读的是:求一段子序列,子序列中的数互为因子数的递增最长序列。

离谱的是:样例 1 3 6 刚好在序列里都有,害。

总结:不要盲目看样例猜题了

以上均为吐槽

进入正题,其实简单,按照筛法的调和级数趋近于nlgn的思路,将下标用调和级数判断,这样因子数可以预处理出来,剩下的用个dp转移一下最长子序列就可以了。1e5之前因子最多240个,复杂度:lim->O(240*n)

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include 
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
ll dp[maxn];
vectorv[maxn];
int main()
{
    int T;scanf("%d",&T);
    while(T--){
        read(n);
        ll maxl=0;
        for(int i=1;i<=n;i++) read(num[i]);
        for(int i=1;i<=n;i++) v[i].clear();
        for(int i=1;i<=n;i++)
            for(int k=i*2;k<=n;k+=i)
                if(num[k]>num[i])
                    v[k].push_back(i);
        for(int i=1;i<=n;i++){
            dp[i]=1;
            for(int x:v[i]){
                dp[i]=max(dp[i],dp[x]+1);
            }
            maxl=max(maxl,dp[i]);
        }
        printf("%lld\n",maxl);
    }
    return 0;
}

C. Orac and LCM

题目大意:

定义lcm为两个数的最小公倍数,问所有对的最小公倍数的最大公约数是多少?

题目思路:

开始思路是对的,越调越离谱

最大公约数与最小公倍数绝对考虑唯一分解定理,考虑每一个质因子的贡献:

Suppose \ X= p1^{a1} \ Y = p1^{a2}

LCM = p1^{max(a1,a2)}

GCD=p1^{min(a1,a2)}

所以:

所以由此看出只需要找组合中每一个p1因子的幂可能出现的最小值

1.如果出现有两个以上的数不存在该质因子,那么此时这两数lcm p1的幂为0,也就是说最大公约数p1的幂为0

2.如果出现有一个不存在该质因子,那么该质因子与最小的组合,即为最小幂

3.如果所有数都有该质因子,那么该质因子最小幂为第二小(不难理解吧)

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include 
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
int prime[maxn];
int vis[maxn];
int cnt=0;
vectorg[maxn];
void set_prime()
{
    for(int i=1;i1) g[temp].push_back(1);
    }
    ll ans=1;
    for(int i=1;i<=cnt;i++){
        if(g[prime[i]].size()<=n-2) continue;
        sort(g[prime[i]].begin(),g[prime[i]].end());
        if(g[prime[i]].size()==n-1) ans=ans*qpow(prime[i],g[prime[i]][0]);
        else ans=ans*qpow(prime[i],g[prime[i]][1]);
    }
    printf("%lld\n",ans);
    return 0;
}
/**
3 4 4 4 2
**/

D. Orac and Medians

题目大意:

给定一个操作,可以使任意一个子区间的数变为该子区间的中位数,问可不可以使得序列最后都变为m

题目思路:

这题 ,emmm,太多的不应该,总结:不要思维僵化。

正题:

首先,这个题目考虑如何呢?

推论1:当有两个相同相连的数的时候,那么整个序列都可以变为相同的数,扩张即可。

1.所以首先思路考虑,只要找到一个区间,长度大于等于2,使得该区间的中位数为m,那么就肯定yes,因为长度大于等于2完全可以靠推论1进行扩张

2.然后就wa了,解释:

首先注意看题目,中位数取在了(x+1)/2,也就是说当区间长度为2时,只要有一个比他大的就可以。

所以我们在第一步上进行扩充:只要存在一长度大于等于2的区间,该区间的中位数>=m,并且此时序列中有m存在,那么一定可以。

3.接下来,因为条件放松了,那么判断也就放松了:

  • 当a[i]>=m&&a[i+1]>=m时便形成为一个区间
  • 当a[i]>=m&&a[i+2]>=m时便形成一个区间

其余情况无需考虑,只需要判断最小的奇数与偶数区间即可。

Code:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include 
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
int root[maxn],cnt=0;
ll a[maxn];
int main()
{
    int T;scanf("%d",&T);
    while(T--){
        read(n);read(m);
        int f=0,f1=0;
        for(int i=1;i<=n;i++){
            read(num[i]);
            if(num[i]==m) f1=1;
        }
        for(int i=1;i<=n-2;i++){
            if(num[i]>=m&&num[i+1]>=m) f=1;
            if(num[i]>=m&&num[i+2]>=m) f=1;

        }
        if(!f1){
            printf("no\n");
            continue;
        }
        if(n==1){
            printf("yes\n");
            continue;
        }
       // printf("%d\n",f1);
        if(num[n]>=m&&num[n-1]>=m) f=1;
        if(f) printf("yes\n");
        else printf("no\n");
    }
    return 0;
}
/**
2
4 3
3 1 2 3
**/

Just Another Code:

其实也可以检查一下,长度为3的区间只要存在大于等于m的数两个以上即可:

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#include 
#include
#include
#include
#include
#include
#define debug(x) cout<<#x<<":"< pp;
const ll INF=1e17;
const int maxn=2e5+6;
const int mod=998244353;
const double eps=1e-3;
inline bool read(ll &num)
{char in;bool IsN=false;
in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
ll num[maxn];
int root[maxn],cnt=0;
ll a[maxn];
ll pre[maxn];
int main()
{
    int T;scanf("%d",&T);
    while(T--){
        read(n);read(m);
        int f=0,f1=0;
        for(int i=1;i<=n;i++){
            read(num[i]);
            if(num[i]==m) f1=1;
            pre[i]=pre[i-1];
            if(num[i]>=m) pre[i]++;
        }
        if(!f1){
            printf("no\n");
            continue;
        }
        if(n==1){
            printf("yes\n");
            continue;
        }
        if(n==2){
            sort(num+1,num+1+n);
            if(num[1]==m) printf("yes\n");
            else printf("no\n");
            continue;
        }
        for(int i=3;i<=n;i++)
            if(pre[i]-pre[i-3]>=2) f=1;
        if(f) printf("yes\n");
        else printf("no\n");
    }
    return 0;
}
/**
2
4 3
3 1 2 3
**/

 

你可能感兴趣的:(数论)