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 <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> 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 <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> 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];
vector<int>v[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 <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> 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;
vector<int>g[maxn];
void set_prime()
{
    for(int i=1;i<maxn;i++)
        vis[i]=(i==1?false:true);//假設除了1以外都是素數
    for(int i=2;i<maxn;i++)
    {
        if(vis[i]) prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<maxn;j++)
        {
            vis[i*prime[j]]=false;
            if(i%prime[j]==0) break;//保證被篩的是他最小的質因子
        }
    }
}
ll qpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1) ans=(ans*a);
        b/=2;a=a*a;
    }
    return ans;
}
int main()
{
    set_prime();
    read(n);
    for(int i=1;i<=n;i++) read(num[i]);
    for(int i=1;i<=n;i++){
        ll temp=num[i];
        for(int k=1;k<=cnt&&prime[k]*prime[k]<=temp;k++){
            int x=0;
            while(temp%prime[k]==0){
                temp/=prime[k];
                x++;
            }
            if(x) g[prime[k]].push_back(x);
        }
        if(temp>1) 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 <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> 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 <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> 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
**/

 

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