codeforces 1692H. Gambling

题目大意:
给定一定的序列X1,X2,X3,......,XN,其中给定一个数字与一个区间A,L, R, 对于Xi ,

L=< i <= R, 满足Xj == A 的个数减去不等于A 的个数的最大值,问你A, L, R的具体的值。

分析:

对于每一个数,我们都有取到最大值的可能,所以我们可以开数组Y[], 如果有连续的子段,我们的数组Y[cnt]就是这个连续子段的等于A(当前我们在序列X中假定的等于A的数)的个数,否则,就是等于不等于A 的个数乘上-1,那么问题就变成了,我们要找到一个区间I, J 使得该区间的Y数组的子段和最大;所以有如下的代码;

//AC  code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn = 2e5 + 10;
const int N = 2e5 + 10;
ll x[maxn];
struct node{
    ll val;
    ll pos1;
    ll pos2;
};
struct nodex{
    ll val;
    ll pos;
};
struct vir{
    ll val;
    ll left;
    ll right;
}ans[N];
vector<ll>u[N];
struct nodex miny[N];
struct node y[N];
int main(){
    int t;
    cin>>t;
    while(t--){
        map<ll, int>mp, sts;
        vector<ll>ver;
        ll n;
        cin>>n;
        for(ll i = 1; i <= n; i++){
            scanf("%lld", &x[i]);
            if(mp[x[i]] == 0){
                mp[x[i]]++;
                ver.push_back(x[i]);
                sts[x[i]] = ver.size() - 1;
                u[ver.size() - 1].push_back(i);
            }else{
                int cnt = sts[x[i]];
                u[cnt].push_back(i);
            }
        }
        //cout<<ver.size()<<endl;
        for(int i = 0; i < ver.size(); i++){
            ll num1 = 1;  
            ll sum[N];  sum[0] = 0;  int cnt1 = 0;  y[0].pos1 = y[0].pos2 = u[i][0] - 1;
            for(int j = 0; j < u[i].size() - 1; j++){
                if(u[i][j + 1] - u[i][j] == 1){
                    num1++;
                }else{
                    cnt1++;
                    y[cnt1].val = num1;
                    y[cnt1].pos1 = u[i][j] - num1 + 1;
                    y[cnt1].pos2 = u[i][j];
                    ll num2 = u[i][j + 1] - u[i][j] - 1;
                    cnt1++;
                    y[cnt1].val = (-1)*num2;
                    y[cnt1].pos1 = u[i][j] + 1;
                    y[cnt1].pos2 = u[i][j + 1] - 1; 
                    num1 = 1;
                }
            }
            cnt1++;
            y[cnt1].val = num1;
            y[cnt1].pos1 = y[cnt1 - 1].pos2 + 1;
            y[cnt1].pos2 = y[cnt1].pos1 + num1 - 1;
            for(int j = 1; j <= cnt1; j++){
                sum[j] = sum[j - 1] + y[j].val;
            }            
            miny[0].val = sum[0];
            miny[0].pos = y[0].pos2 + 1;
            for(int j = 1; j <= cnt1; j++){
                if(sum[j] < miny[j - 1].val){
                    miny[j].val = sum[j];
                    miny[j].pos = y[j].pos2 + 1;
                }else{
                    miny[j] = miny[j - 1];
                }
            }
            ll maxv = -1;
            for(int j = 0; j <= cnt1; j++){
                if(sum[j] - miny[j].val > maxv){
                    ans[i].left = miny[j].pos;
                    ans[i].right = y[j].pos2;
                    maxv = sum[j] - miny[j].val;
                    ans[i].val = maxv;
                }
            }
//            printf("%lld\n", ver[i]);
//            for(int j = 0; j <= cnt1; j++){
//                printf("%lld %lld %lld\n", y[j].val, y[j].pos1, y[j].pos2);
//            }
        } 

        int ansid = 0;
        for(int i = 0; i < ver.size(); i++){
            if(ans[i].val > ans[ansid].val){
                ansid = i;
            }
            u[i].clear();
        }
        printf("%lld %lld %lld\n", ver[ansid], ans[ansid].left, ans[ansid].right);
    }
    
    
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值