Codeforces Round #806 (Div. 4) F,G
G
https://codeforces.com/contest/1703/problem/G
做法1
很容易想到dp
用表示打开前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时的
所以做法是贪心——从某个为分界,之前全部选用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
做法:二分!
做法1:用树状数组统计
首先筛走不满足的i,储存合法的pair(,i)然后按升序,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:二分查找
当筛掉不满足的i之后,剩下的不等式只需要满足 即可
那么就把i,分别放进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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】