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;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
"educational codeforces round 103 (rated for div. 2)"是一个Codeforces平台上的教育性比赛,专为2级选手设计评级。以下是有关该比赛的回答。 "educational codeforces round 103 (rated for div. 2)"是一场Codeforces平台上的教育性比赛。Codeforces是一个为程序员提供竞赛和评级的在线平台。这场比赛是专为2级选手设计的,这意味着它适合那些在算法和数据结构方面已经积累了一定经验的选手参与。 与其他Codeforces比赛一样,这场比赛将由多个问题组成,选手需要根据给定的问题描述和测试用例,编写程序来解决这些问题。比赛的时限通常有两到三个小时,选手需要在规定的时间内提交他们的解答。他们的程序将在Codeforces的在线评测系统上运行,并根据程序的正确性和效率进行评分。 该比赛被称为"educational",意味着比赛的目的是教育性的,而不是针对专业的竞争性。这种教育性比赛为选手提供了一个学习和提高他们编程技能的机会。即使选手没有在比赛中获得很高的排名,他们也可以从其他选手的解决方案中学习,并通过参与讨论获得更多的知识。 参加"educational codeforces round 103 (rated for div. 2)"对于2级选手来说是很有意义的。他们可以通过解决难度适中的问题来测试和巩固他们的算法和编程技巧。另外,这种比赛对于提高解决问题能力,锻炼思维和提高团队合作能力也是非常有帮助的。 总的来说,"educational codeforces round 103 (rated for div. 2)"是一场为2级选手设计的教育性比赛,旨在提高他们的编程技能和算法能力。参与这样的比赛可以为选手提供学习和进步的机会,同时也促进了编程社区的交流与合作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值