Codeforces Round #806 (Div. 4) F,G

G

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

nai使good keyaik使bad keyai2for(j=i+1;j<=n;j++) aj=aj2
使n

做法1
很容易想到dp
dp[i][j]表示打开前i个箱子,使用j次bad key,最多能获得多少金币

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100005;
ll a[N];
int n;
ll t,k;
ll dp[N][33];

int main(){
    cin>>t;
    while(t--){
        cin>>n>>k;
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
        }

        ll ans=-1e18;
        for(int i=0;i<=30;i++) dp[0][i]=0;
        for(int i=1;i<=n;i++){
            for(int j=0;j<=min(30,i);j++){
                if(j==0) dp[i][j]=dp[i-1][j]+(a[i]>>j)-k;
                else dp[i][j]=max(dp[i-1][j]+(a[i]>>j)-k,dp[i-1][j-1]+(a[i]>>(j)));

                ans=max(ans,dp[i][j]);
            }
        }
        
        printf("%lld\n",ans);
    }
    system("pause");
    return 0;
}

做法2
容易发现当n=2时,假如只能选用一次good key一次bad key,当顺序为gb时的答案优于bg时的
所以做法是贪心——从某个ai为分界,之前全部选用good key,之后全部选用bad key,求最大值

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=100005;
int a[N];
int n;
ll t,k;
ll pre[N];

int main(){
    cin>>t;
    while(t--){
        cin>>n>>k;
        pre[0]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pre[i]=pre[i-1]+a[i];
        }

        //先用good key,后面全用bad key
        ll ans=-1e18;
        for(int i=0;i<=n;i++){
            ll tem=pre[i]-1ll*k*i;
            for(int j=i+1;j<=min(n,i+31);j++){
                tem+=(a[j]>>(j-i));
            }
            ans=max(ans,tem);
        }
        printf("%lld\n",ans);
    }
    system("pause");
    return 0;
}

F

https://codeforces.com/contest/1703/problem/F
2·105,ai<i<aj<j(i,j)
做法:二分!

做法1:用树状数组统计
首先筛走不满足ai<i的i,储存合法的pair(ai,i)然后按ai升序,i降序的顺序排列
细节见代码

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9+7,N = 200005;
int t,n;
int a[N];
ll c[N];
bool vis[N];
vector<pair<int,int> >v;

bool cmp(pair<int,int>a,pair<int,int>b){
    if(a.first!=b.first) return a.first<b.first;
    else return a.second>b.second;
}

int lowbit(int x){
	return x&-x;
}

void upd(int x,int k){
	while(x<=n){
		c[x]+=k;
		x+=lowbit(x);
	}
}

//求sum[1..x] 
ll sum(int x){
	ll res=0;
	while(x){
		res+=c[x];
		x-=lowbit(x);
	}
	return res;
}

int main(){
    cin>>t;
    for(int tt=1;tt<=t;tt++){
        v.clear();
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i]<i) vis[i]=1;
            else vis[i]=0;
            if(vis[i]) v.push_back({a[i],i});
        }
        sort(v.begin(),v.end(),cmp);
        ll ans=0;
        for(int i=0;i<v.size();i++){
            pair<int,int>now=v[i];
            int tem=now.first-1;
            if(tem>0) ans+=sum(tem);
            upd(now.second,1);
        }
        printf("%lld\n",ans);

        for(int i=0;i<=n;i++) c[i]=0;
    }

    system("pause");
    return 0;

}

(1有点复杂)
做法2:二分查找
当筛掉不满足ai<i的i之后,剩下的不等式只需要满足i<aj 即可
那么就把i,ai分别放进vector中,排序后二分查找即可

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int mod = 1e9+7,N = 200005;
int t,n;
int a[N];
bool vis[N];
vector<int>v,id;

bool cmp(int a,int b){
    return a<b;
}

int main(){
    cin>>t;
    for(int tt=1;tt<=t;tt++){
        v.clear(); id.clear();
        cin>>n;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(a[i]<i) vis[i]=1;
            else vis[i]=0;
            if(vis[i]) v.push_back(a[i]),id.push_back(i);
        }
        sort(v.begin(),v.end());
        sort(id.begin(),id.end());

        ll ans=0;
        for(auto i:id){
            ans+=v.size()-(upper_bound(v.begin(),v.end(),i)-v.begin());
        }
        printf("%lld\n",ans);
    }

    system("pause");
    return 0;

}

posted @   starlightlmy  阅读(49)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示