Codeforces Round 922 (Div. 2)(A-D)

文章讨论了如何使用贪心算法和动态规划解决涉及数组操作的问题,包括对元素进行排序、计算最优交换操作以及找到满足特定条件的最大值。作者展示了如何利用这些方法处理给定的编程题目实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A 直接全用横着放

偶数列全放两个,奇数列最后放三个

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;

int n,m,k;

void solve()
{
    cin>>n>>m;
    if(m%2==0) cout<<n*(m/2)<<"\n";
    else {
        cout<<n*((m-1)/2)<<"\n";
    }
} 

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
  
    cin>>t;

    while(t--) solve();
}

B.

我想的是对每个ai 和bi单独思考,因为可以随便排

考虑一对位置 i,j 交换

ai>aj and bi>bj  交换减少两对

ai>aj and bi<bj 无变化

ai<aj and bi<bj 增加两个

ai<aj and bi>bj 无变化

所以我是按ai逆序对数量+bi逆序对排的

越大的数在越后面逆序对越小

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;

int n,m,k;
PII a[N];
int c[N];
void solve()
{
  cin>>n;
  for(int i=1;i<=n;i++) cin>>a[i].first;
  for(int i=1;i<=n;i++) cin>>a[i].second;
  sort(a+1,a+1+n,[&](const auto&p,const auto&q){
      return p.first+p.second<q.first+q.second;
  });
    for(int i=1;i<=n;i++){
        cout<<a[i].first<<" \n"[i==n];
    }
    for(int i=1;i<=n;i++){
        cout<<a[i].second<<" \n"[i==n];
    }
} 

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
  
    cin>>t;

    while(t--) solve();
}

C:

这个题力扣好像似曾相似ahhh

就是贪心从大到小如果第i位无法避免是 0  1,你x的第i位无论取什么一定存在这个差值

所以记录当前位是a还是b

后面全部位都让另一个进来变大

比如 2^4>=2^3+2^2+2^1+2^0

#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
using node=tuple<int,int,int>;
const long long inf=1e18;

int n,m,k;
PII a[N];
int c[N];
void solve()
{
//   cin>>n;
//   for(int i=1;i<=n;i++) cin>>a[i].first;
//   for(int i=1;i<=n;i++) cin>>a[i].second;
//   for(int i=1;i<=n;i++){
       
//   }
    int a,b,n;
    cin>>a>>b>>n;
    auto get=[&](int a,int b)->int{
        int x=0;
        int now=-1;
        for(int i=60;i>=0;i--)
        {
            int l=(a>>i&1),r=(b>>i&1);
            if(l==r) continue;
            if(now!=-1)
            {
                if(now==a){
                    if(r==0&&x+(1ll<<i)<=n)
                    {
                        x+=(1ll<<i);
                    }
                }   
                else{
                    if(l==0&&x+(1ll<<i)<=n)
                    {
                        x+=(1ll<<i);
                    }
                }
            }
            if(now==-1)
            {
                if(l==0)
                {
                    now=b;
                }else{
                    now=a;
                }
            }

        }
        return abs((a^x)-(b^x));
    };

    int res=get(a,b);
    swap(a,b);
    cout<<min(get(a,b),res)<<"\n";
} 

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
  
    cin>>t;

    while(t--) solve();
}

D:

可以想到得是答案是有单调性得,因为是取max,答案越大能完成可能性越大

然后check函数里面可以dp

dp状态就是:前1-i个数里面最小需要提出来的数得元素总和

那么f[i] 第i个位置可以提出去也可以不提出去

假设提出去第i个位置 f[i]=f[j-1]+a[i]

更一般得

假设当前提得是   j [            i]

s[i]-s[j]里面得总和小于等于x,那么j这个位置可以提出去

如果提出去代价就是f[j-1] + a[j]代表a[j]这个数一定要提出去

然后代码里注释的就是暴力,观察可以得到优化可以单调队列或者线段树或者优先队列都是可以得

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

const long long inf=1e18;

int n,m,k;
int a[N],s[N],b[N];

void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
    auto check=[&](int x)
    {
        vector<int> f(n+10,2e18);
        f[0]=0;
        for(int i=1,j=0;i<=n;i++){
            j+=a[i];
            if(j<=x){
                f[i]=0;
            }else break;
        }
        int idx=0;
        priority_queue<PII,vector<PII>,greater<PII>> q;
        for(int i=1;i<=n;i++)
        {
            f[i]=min(f[i],f[i-1]+a[i]);
            while(q.size()&&s[i]-s[q.top().second]>x){
                q.pop();
            }
            if(q.size())
            f[i]=min(f[i],q.top().first);
            q.emplace(f[i-1]+a[i],i);
            
            // for(int j=1;j<=i;j++)
            // {
            //   if(s[i]-s[j]<=x)
            //   f[i]=min(f[i],f[j-1]+a[j]);
            // }
        }

        return f[n]<=x;
    };
    int l=*max_element(a+1,a+1+n),r=s[n];
    while(l<r){
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l<<"\n";
    
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
  
    cin>>t;

    while(t--) solve();
}
#include<bits/stdc++.h>
using namespace std;
const int N = 3e5+10,M=2*N,mod=1e9+7;
#define int long long
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;

const long long inf=1e18;

int n,m,k;
int a[N],s[N],b[N];
struct node{
    int l,r;
    int v;
}tr[N*4];
void pushup(int u)  // 由子节点的信息,来计算父节点的信息
{
    tr[u].v = min(tr[u << 1].v, tr[u << 1 | 1].v);
}

void build(int u, int l, int r)
{
    tr[u] = {l, r,inf};
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

int query(int u, int l, int r)
{
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].v;   // 树中节点,已经被完全包含在[l, r]中了
    
    int mid = tr[u].l + tr[u].r >> 1;
    int v = 2e18;
    if (l <= mid) v = query(u << 1, l, r);
    if (r > mid) v = min(v, query(u << 1 | 1, l, r));

    return v;
}

void modify(int u, int x, int v)
{
    if (tr[u].l == x && tr[u].r == x) tr[u].v = v;
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (x <= mid) modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);
        pushup(u);
    }
}

void solve()
{
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],s[i]=s[i-1]+a[i];
    auto check=[&](int x)
    {
        build(1,1,n);
        vector<int> f(n+10,2e18);
        f[0]=0;
        for(int i=1,j=0;i<=n;i++){
            j+=a[i];
            if(j<=x){
                f[i]=0;
            }else break;
        }
        int idx=0;
        for(int i=1;i<=n;i++)
        {
            f[i]=min(f[i],f[i-1]+a[i]);
            while(idx<=i&&s[i]-s[idx]>x){
                idx++;
            }
            f[i]=min(f[i],query(1,idx,i));
            modify(1,i,f[i-1]+a[i]);
            // for(int j=1;j<=i;j++)
            // {
            //   if(s[i]-s[j]<=x)
            //   f[i]=min(f[i],f[j-1]+a[j]);
            // }
        }

        return f[n]<=x;
    };
    //cout<<check(7)<<"\n";
    int l=*max_element(a+1,a+1+n),r=s[n];
    while(l<r){
        int mid=l+r>>1;
        if(check(mid)) r=mid;
        else l=mid+1;
    }
    cout<<l<<"\n";
    
}

signed main()
{
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
  
    cin>>t;

    while(t--) solve();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值