codeforces1027 Build an Array题解

题目链接:

https://codeforces.com/contest/2114/problem/G

思路:

首先观察的重要的一个性质就是一个数最少需要一次,最多则与他能被\(2\)整除多少次有关。

比方说一个数可以分解成\(2^n*x\)的形式,那这个就可以一直放\(x\)实现最多的\(2^n\)次。

并且这个次数从\(1\)\(2^n\)每个数都能取到,原因就是你可以把他看作一颗二叉树,每次\(÷2\)就像二叉树分出两个儿子,然后这样会使得叶子节点个数\(+1\),所以都能取到。
所以只要\(n\leq k \leq\)(每个数的次数和)。因为题目条件\(n\leq k\),所以只要\(k \leq\)(每个数的次数和)就可以,否则就不行。

但你看样例直接统计每个数的最大次数然后加起来这样是不对的,比如说数组是\(2,1,4\)则会发现如果一直插\(1\),中间的\(1\)一定会合并,从此可以看出,如果我现在构造某个数时,旁边有和我能分解成同一个结构的\(2^i*x\)的,且比我小我就会损失次数,我最好要避免这种情况,比如\(12,3\)我先弄出\(12\)优于先弄出\(3\)
于是首先弄出谁是至关重要的,因为这会决定构造每个数时自己的邻居是谁,第一个数确定每个数的邻居也就确定了。\(A,B,C,D\),用箭头指向代表邻居则有
\(A\leftarrow B \leftarrow C \leftarrow D\)\(A\rightarrow B \leftarrow C \leftarrow D\)
\(A\rightarrow B \rightarrow C \leftarrow D\)\(A\rightarrow B \rightarrow C \rightarrow D\)
\(4\)种情况。
然后我现在在构造\(2^a*X\),邻居是\(2^b*X\),我就要先生成一个\(2^{b+1}*X\)来隔离这个邻居,因为放任何比这小的都无法构造,这时候我构造这个数就只能产生\(2^a-2^{b+1}+1\)的次数了。然后我就要枚举谁第一个生成。但直接枚举会超时,然后观察发现,每种情况都是两段两种方向的箭头拼在一起,这个可以前后缀预处理。
代码里我用\(dp\)维护产生该数的最多次数,\(who\)维护除去\(2^n\)的部分我是谁,\(pre\)是我的邻居是我左边的数,\(suf\)是邻居是我右边的数。处理好后,求最大次数则用$ ans=max(ans,dp[i]+suf[1]-suf[i]+pre[n]-pre[i])$求出最多次数即可。

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=100010;
int v[N];
int dp[N];
int who[N];
void solve(){
    int n,k;cin>>n>>k;
    for(int i=1;i<=n;i++){
        cin>>v[i];
    }
    for(int i=1;i<=n;i++){
        int x=v[i];dp[i]=1;
        while(x%2==0){
            x/=2;
            dp[i]*=2;
        }   
        who[i]=x;
    }who[n+1]=0;
    vector<int>pre(n+2),suf(n+2);
    int ans=0;
    for(int i=1;i<=n;i++){
        if(who[i]==who[i-1]&&v[i]>v[i-1]){
            pre[i]=pre[i-1]+dp[i]-dp[i-1]*2+1;
        }else pre[i]=pre[i-1]+dp[i];
    }
    for(int i=n;i>=1;i--){
        if(who[i+1]==who[i]&&v[i]>v[i+1]){
            suf[i]=suf[i+1]+dp[i]-dp[i+1]*2+1;
        }else suf[i]=suf[i+1]+dp[i];
    }
    for(int i=1;i<=n;i++){
        ans=max(ans,dp[i]+suf[1]-suf[i]+pre[n]-pre[i]);
    }
    if(ans>=k){
        cout<<"YES"<<endl;
    }else cout<<"NO"<<endl;
}
signed main(){
#ifdef ONLINE_JUDGE
#else
    freopen("in.in","r",stdin);
    freopen("out.out","w",stdout);
#endif
ios::sync_with_stdio(false);cin.tie(0);
    int T;cin>>T;
    while(T--){
        solve();
    }
}
posted @ 2025-06-01 20:18  cbbdhz  阅读(24)  评论(0)    收藏  举报