Educational Codeforces Round 165 (Rated for Div. 2)(C dp D贪心 E二维扫点)

C:

由于确定了使用那个最小值,那么他只会单调往左推或者往右推,所以dp

前i个点使用j次的最小值即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=1e18;
typedef pair<int,int> PII;
typedef long long LL;
using Node=tuple<int,int,int,int>;
using node=tuple<int,int,int,int>;
int n,m,k;
int a[N];
void solve()
{
    cin>>n>>m;
    vector<vector<int>> f(n+10,vector<int>(m+10,inf));
    for(int i=1;i<=n;i++) cin>>a[i];
    f[0][0]=0;
    for(int i=1;i<=n;i++){
        for(int j=0;j<=m;j++)
        {
            f[i][j]=f[i-1][j]+a[i];
            for(int k=i-1;k>=1;k--)
            {
                if(i-k<=j)
                {
        f[i][j]=min(f[i][j],f[k][j-(i-k)]+(i-k)*a[k]);
        f[i][j]=min(f[i][j],f[k-1][j-(i-k)]+(i-k+1)*a[i]);
                }else break;
            }    
        }
    }
  
    int res=inf;
    for(int i=0;i<=m;i++)
    res=min(res,f[n][i]);
    cout<<res<<"\n";
}
 
signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
    return 0;
}

D:如果物品确定,那么Bob为了最小化b数组的总和,肯定最最大的k个b

而alice则会最小化这k个b的a

所以枚举分界点即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=1e18;
typedef pair<int,int> PII;
typedef long long LL;
using Node=tuple<int,int,int,int>;
using node=tuple<int,int,int,int>;
int n,m,k;
PII a[N];
int b[N],c[N];
void solve()
{
    vector<PII> a;
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>b[i];
    for(int i=1;i<=n;i++) cin>>c[i];
    for(int i=1;i<=n;i++){
        if(c[i]-b[i]>=0)
        a.emplace_back(b[i],c[i]);
    }
    sort(a.begin(),a.end(),[&](const auto&p,const auto&q){
        return p.second>q.second;
    });
    if(a.size()<=k){
        cout<<0<<"\n";return ;
    }
    multiset<int> st;
    //priority_queue<PII> q;
    int now=0,res=0;
    int s1=0,s2=0;
    for(int i=0;i<k;i++)
    {
        st.insert(a[i].first);
        s1+=a[i].first;
        //s2+=a[i].second-a[i].first;
    }
    for(int i=k;i<a.size();i++){
        s2+=a[i].second-a[i].first;
    }
    //for(auto [x,y]:a) cout<<x<<" "<<y<<"\n";
    //cout<<s1<<" "<<s2<<"\n";
    for(int i=k;i<a.size();i++)
    {
        res=max(res,s2-s1);
        s2-=(a[i].second-a[i].first);
        st.insert(a[i].first);
        s1+=a[i].first;
        s1-=*st.rbegin();
        st.extract(*st.rbegin());
    }
    cout<<res<<"\n";
}

signed main(){
    cin.tie(0);cout.tie(0);ios::sync_with_stdio(0);
    int t=1;
    cin>>t;
    while(t--) solve();
    return 0;
}

E:

问题转成二维扫点

有个结论:如果某个点到右端点不符合要求,那么只需要修改这个点就能保证前面的点都一定符合

要求,即每个右端点存在一个最近的不符合的点,只需要修改一次即可

且肯定要修改最大的左端点

所以用扫描线求出来最右的左端点即可

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,M=2*N,mod=1e9+7;
#define int long long
#define uLL unsigned long long
const long long inf=1e18;
typedef pair<int,int> PII;
typedef long long LL;
using node=tuple<int,int,int>;
int n,m,k;
int a[N];
class segment{
    #define lson (u << 1)
    #define rson (u << 1 | 1)
    public:
    int n;
    vector<int> mn,add,pos;
    segment(int _n) : n(_n) {
        mn.resize(n*4+10,inf);
        pos.resize(n*4+10);
        add.resize(n*4+10);
        build(1,1,n);
    }
    void pushup(int u){
        mn[u]=min(mn[lson],mn[rson]);
        if(mn[u]==mn[rson]) pos[u]=pos[rson];
        else pos[u]=pos[lson];
    }
    void build(int u, int l, int r){
        if (l == r)
        {
            add[u]=0;
            mn[u]=0;
            pos[u]=l;
            return ;
        }
        int mid = (l + r) >> 1;
        build(lson, l, mid);
        build(rson, mid + 1, r);
        pushup(u);
    }
    void pushdown(int u)
    {
        if(add[u]){
            add[lson]+=add[u];
            add[rson]+=add[u];
            mn[lson]+=add[u];
            mn[rson]+=add[u];
        }
        add[u]=0;
    }
    void modify(int u, int l, int r, int L,int R, int val){
        if (l>=L&&r<=R)
        {
            add[u]+=val;
            mn[u]+=val;
            return;
        }
        pushdown(u);
        int mid = (l + r) >> 1;
        if (L <= mid) modify(lson, l, mid, L,R, val);
        if(R>mid) modify(rson, mid + 1, r,L ,R, val);
        pushup(u);
    }
    //二分线段树
    PII query(int u,int l,int r,int L,int R)
    {
        if(L<=l&&r<=R) return {mn[u],pos[u]};
        pushdown(u);
        int mid=l+r>>1;
        PII res={inf,0};
        PII ans={inf,0};
        if(L<=mid) res=query(lson,l,mid,L,R);
        if(R>mid) ans=query(rson,mid+1,r,L,R);
        res.first=min(res.first,ans.first);
        if(res.first==ans.first) res.second=ans.second;
        return res;
    }
};
void solve()
{
    cin>>n;
    vector<int> pre(n+1),nxt(n+1);
    for(int i=1;i<=n;i++) cin>>a[i];
    {
        vector<int> last(n+1);
        for(int i=1;i<=n;i++){
            pre[i]=last[a[i]];
            last[a[i]]=i;
        }
    }
    {
        vector<int> last(n+1,n+1);
        for(int i=n;i>=1;i--){
            nxt[i]=last[a[i]];
            last[a[i]]=i;
        }
    }
    vector<vector<PII>> pos(n+1);
    for(int i=1;i<=n;i++)
    {
        pos[nxt[i]-1].push_back({i,1});
        pos[i-1].push_back({i,0});
    }
    segment tr(n);
    set<PII> st;
    for(int i=n;i>=1;i--)
    {
        for(auto [x,type]:pos[i]){
            if(type) tr.modify(1,1,n,pre[x]+1,x,1);
            else tr.modify(1,1,n,pre[x]+1,x,-1);
        }
        auto [mn,mnpos]=tr.query(1,1,n,1,i);
        if(mn==0){
           // cout<<mnpos<<"\n";
            st.insert({mnpos,i});
        }
    }
    int ans=0;
    int cur=n+1;
    while(st.size()){
        if(prev(st.end())->second>=cur) 
        st.erase(prev(st.end()));
        else{
            ans++;
            cur=prev(st.end())->first;
            st.erase(prev(st.end()));
        }
    }
    cout<<ans<<"\n";
}

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

    while(t--) solve();
    return 0;
}
相关推荐
杜杜的man1 分钟前
【go从零单排】迭代器(Iterators)
开发语言·算法·golang
小沈熬夜秃头中୧⍤⃝18 分钟前
【贪心算法】No.1---贪心算法(1)
算法·贪心算法
木向1 小时前
leetcode92:反转链表||
数据结构·c++·算法·leetcode·链表
阿阿越1 小时前
算法每日练 -- 双指针篇(持续更新中)
数据结构·c++·算法
skaiuijing1 小时前
Sparrow系列拓展篇:对调度层进行抽象并引入IPC机制信号量
c语言·算法·操作系统·调度算法·操作系统内核
Star Patrick1 小时前
算法训练(leetcode)二刷第十九天 | *39. 组合总和、*40. 组合总和 II、*131. 分割回文串
python·算法·leetcode
武子康3 小时前
大数据-214 数据挖掘 机器学习理论 - KMeans Python 实现 算法验证 sklearn n_clusters labels
大数据·人工智能·python·深度学习·算法·机器学习·数据挖掘
pianmian18 小时前
python数据结构基础(7)
数据结构·算法
好奇龙猫10 小时前
【学习AI-相关路程-mnist手写数字分类-win-硬件:windows-自我学习AI-实验步骤-全连接神经网络(BPnetwork)-操作流程(3) 】
人工智能·算法
sp_fyf_202410 小时前
计算机前沿技术-人工智能算法-大语言模型-最新研究进展-2024-11-01
人工智能·深度学习·神经网络·算法·机器学习·语言模型·数据挖掘