Codeforces Round 961 (Div. 2)

A

#include<bits/stdc++.h>
using namespace std;
int a[200];
void solve(){
    int n,k;cin>>n>>k;
    a[1]=n;
    for(int j=n-1,i=2;i<=1+(n-1)*2;i+=2,j--){
        a[i]=a[i+1]=j;
    }
    if(!k){
        cout<<0<<"\n";
        return;
    }
    for(int i=1;i<=1+(n-1)*2;i++){
        k-=a[i];
        if(k<=0) {
            cout<<i<<"\n";
            return ;
        }
    }
}
int main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        //TODO
        solve();
    }
}

B1

考虑双指针,固定左端点 l 然后维护最大的右端点 r 使得 a[r]-a[l]<=1 ,且能凑的花瓣数尽量多。

但是特判没写好,双指针寄了,最后先过了B2,改的B2代码过的B1

B2

考虑都买第一种,剩下的钱再买第二种,还有剩的话考虑加钱把之前买的第一种看能不能升级成第二种(价格只差1,且收益和价格一样,相当于在原来的基础上多花一块钱就能多拿一个花瓣)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
#define int long long
struct node{
    int v,num;
}a[N];
bool cmp(node a,node b){
    return a.v<b.v;
}
void solve(){
    int n,m;cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>a[i].v;
    for(int i=1;i<=n;i++) cin>>a[i].num;
    
    sort(a+1,a+n+1,cmp);

    int ans=0;
    for(int i=1;i<=n-1;i++){
        int t1=m/a[i].v;
        t1=min(t1,a[i].num);
        ans=max(ans,t1*a[i].v);
        if(a[i+1].v!=a[i].v+1) continue;
        int left=m-t1*a[i].v;
        int t2=left/a[i+1].v;
        t2=min(t2,a[i+1].num);
        ans=max(ans,t1*a[i].v+t2*a[i+1].v);
        left-=t2*a[i+1].v;
        if(left && t2<a[i+1].num ){
            int add=a[i+1].num-t2;
            add=min(add,min(t1,left));
            ans=max(ans,t1*a[i].v+t2*a[i+1].v+add);
        }
    }
    int t1=m/a[n].v;
    t1=min(t1,a[n].num);
    ans=max(ans,t1*a[n].v);
    cout<<ans<<"\n";
    // spj n
}
// 1 1 1 2 4 5 6 7
signed main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    int t;cin>>t;
    while(t--){
        //TODO
        solve();
    }
}

C

有人说是典中典,可能做题太少了没见过类似的,觉得还挺有意思。

首先不能暴力扩大,数值很快就爆炸了(实测8 7 6 5 4 3 2 1寄得飞快)

第一次想到了取对数后得到

(偷了其他博主的图)

但是这个式子还是不会处理,没想到再取一次对数变成

然后换了思路,不能维护真实数值的话显然要从原本的值入手

维护一个cnt数组,cnt[i]表示a[i]平方了几次。

考虑 a[i] < a[i-1] ,显然a[i]的大小要先大于等于a[i] ,这个可以暴力求 

然后a[i-1]做了cnt[i-1]次,a[i] 也要跟着做cnt[i-1] 次

a[i]>a[i-1]同理 ,讨论下此时a[i-1]的真实值是否大于a[i] ,若没有大于则不管

若大于了则a[i]也要一起做cnt[i-1]次,但又因为a[i]的初值比a[i-1]大,所以还要扣掉这部分

具体细节见代码

#include<bits/stdc++.h>
using namespace std;
const int N =2e5+5;
#define int long long
int a[N],cnt[N],b[N];
void solve(){
    int n;cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],cnt[i]=0;
    int ans=0;
    for(int i=2;i<=n;i++){
        if(a[i]<a[i-1]){
            if(a[i]==1) {
                cout<<-1<<"\n";
                return;
            }
            cnt[i]=cnt[i-1];
            int tot=0;
            int tmp=a[i];
            while(tmp<a[i-1]){
                tmp=tmp*tmp;
                tot++;
            }
            cnt[i]+=tot;
        }
        else {
            if(a[i]==a[i-1]) {
                cnt[i]=cnt[i-1];
            }
            else { // a[i]>a[i-1]    
                int need=0,c=a[i-1],d=a[i];
                if(c==1) continue;
                while( c<d ){
                    c=c*c;
                    need++;
                }
                //cout<<i<<" :: "<<c<<" "<<d<<" "<<cnt[i-1]<<"\n";
                if(c==d){
                    if(need<=cnt[i-1]) { // a[i] > a[i-1]
                        cnt[i]=cnt[i-1]-need;
                    }
                    else cnt[i]=0;
                }
                else if(c>d){
                    if(need<=cnt[i-1]) { // a[i] > a[i-1]
                        cnt[i]=1+cnt[i-1]-need;
                    }
                    else cnt[i]=0;    
                }
            }
        }
    }
    
    for(int i=1;i<=n;i++){
            ans+=cnt[i];    
    }
    cout<<ans<<"\n";
}
signed main(){
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    
    int t;cin>>t;
    while(t--){
        //TODO
        solve();
    }
}

 

posted @ 2024-07-24 10:56  liyishui  阅读(59)  评论(0编辑  收藏  举报