Codeforces Round #602 部分题解

欢迎进入博客浏览
>>我的博客<<
更好的排版,更好的阅读体验

Codeforces Round #602

A. Math Problem

题意:

In other words, you need to find a segment [ a ; b ] [a;b] [a;b], such that [ a ; b ] [a;b] [a;b] and every [ l i ; r i ] [li;ri] [li;ri] have a common point for each i i i, and b − a b−a ba is minimal.

思路:

最左的右端连接做右的左端

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define REP(i, lim) for(int i=0;i<lim;++i)
#define REPP(i, lim) for(int i=1;i<=lim;++i)
#define DEC(i, lim) for(int i=lim;i>=1;--i)
#define FOR(i,l,r)  for(int i=l;i<r;++i)
#define deBug cout<<"==================================="<<endl;
#define clr(s) memset(s, 0, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
const int MAXN = 1000055;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
 
int a, b;
int n;
 
int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
 
    int T;
 
    cin>>T;
 
    while(T--) {
        cin>>n;
        int maxa = -inf, minb = inf;
        REP(i, n) {
            cin>>a>>b;
            maxa = max(maxa, a);
            minb = min(minb, b);
        }
        if(maxa-minb>0) cout<<maxa-minb<<endl;
        else                cout<<0<<endl;
    }
    return 0;
}

B. Box

题意

一个n项的排列组合,已知所有前 n n n项的最大值 [ q 0 , q 1 , . . . , q n ] [q_0,q_1,...,q_n] [q0,q1,...,qn],求任意可行解,无解输出-1。

思路:

  • 对于一个可行解,第 n n n项的值 a i a_i ai必须低于等于 i i i

  • 保证解可行后,将首次出现的最大值输出,中间以此插入从小到大的未出现值。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define REP(i, lim) for(int i=0;i<lim;++i)
#define REPP(i, lim) for(int i=1;i<=lim;++i)
#define DEC(i, lim) for(int i=lim;i>=1;--i)
#define FOR(i,l,r)  for(int i=l;i<r;++i)
#define deBug cout<<"==================================="<<endl;
#define clr(s) memset(s, 0, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
const int MAXN = 1000055;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

int n;
int pre[MAXN], v[MAXN];

int main()
{
//    freopen("out.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
    std::ios::sync_with_stdio(false);

    int T;
    cin>>T;
    while(T--)
    {
        cin>>n;
        int flag = 1;
        REP(i,n+1) v[i] = 0;
        REPP(i, n) {
            cin>>pre[i];
            if (pre[i] < i) flag = 0;
        }

        if(flag == 0) cout<<-1<<'\n';
        else {
            int cur = 1;
            REPP(i, n){
                if(!v[pre[i]])  cout<<pre[i]<<' ', v[pre[i]] = 1;
                else {
                    for (int j = cur; j <= pre[i]; ++j) {
                        if (!v[j]) {
                            cout<<j<<' ';
                            v[j] = 1; cur = j+1;
                            break;
                        }
                    }
                }
            }
            cout<<'\n';
        }
    }

    return 0;
}

C. Messy

题意:

给定一个长度为 n n n的括号序列,每次操作可以将 [ l , r ] [l, r] [l,r]之间的符号顺序反转,既 ( ( ) (() (()变成 ) ( ( )(( )((

要求在n补内,使序列满足以下条件:

  • 整个序列是合法序列。
  • 序列的所有前缀(包括他自己)中恰好有 k k k个合法序列。

题目保证一定有解,输入正好一半左括号一半右括号,注意:题目不用求最少步骤

思路:

恰好 k k k个合法序列,既前缀合法有 k − 1 k-1 k1种。

既满足以下形式的序列可行:
( ) ( ) ( ( ( ( ( ) ) ) ) ) ()()((((())))) ()()((((()))))
数据不大,暴力构造就可以。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define REP(i, lim) for(int i=0;i<lim;++i)
#define REPP(i, lim) for(int i=1;i<=lim;++i)
#define DEC(i, lim) for(int i=lim;i>=1;--i)
#define FOR(i,l,r)  for(int i=l;i<r;++i)
#define deBug cout<<"==================================="<<endl;
#define clr(s) memset(s, 0, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
const int MAXN = 1000055;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

int k, n;
char alp;
vector<char> vec;

char get(int i) {
    if(i<2*(k-1))   return i%2 ? ')':'(';
    else            return i<(n/2+k-1) ? '(':')';
}

struct {int a, b;} node[MAXN];

int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);

    int T;
    scanf("%d", &T);
    while(T--)
    {
        vec.clear();
        scanf("%d%d", &n, &k);

        getchar();
        REP(i, n) { scanf("%c", &alp); vec.push_back(alp); }

        int index = 0;
        REP(i, n) {
            char cur = get(i);
            if(vec[i]!=cur) {
                int k;
                for(k=i+1;k<n;++k) if(vec[k]==cur) break;
                reverse(vec.begin()+i, vec.begin()+k+1);
                node[index].a = i+1;
                node[index++].b = k+1;
            }
        }
        printf("%d\n", index);
        REP(i, index) printf("%d %d\n", node[i].a, node[i].b);
    }
    return 0;
}

D. Optimal Subsequences (Hard Version)

题意:

给定一个长度为 n n n的正整数序列,进行 m m m次查询,每次查询给定 k k k p o s pos pos,求得一个子序列,要求:

  • 子序列长度为 k k k,并且各项和最大。
  • 和相同的情况,求出字典序最小的子序列。

输出子序列的第 p o s pos pos项。

思路:

显然易见,所求子序列的和为序列中前 k k k最大项的和,那么子序列中的数字就可以确定。在确定了子序列的各项值,既可以一步一步构造满足要求的子序列。

题目要求字典序最小,所求子序列为元序列的排序后前 k k k个数字,则组成为取所有最大值,然后取所有第二大值,直到去到第 k k k个值,在取到第 n n n大值之前,前面的值在原序列所有出现都会被放到子序列中,那么关键就是(有可能)又有取完的第 k k k大值怎么取。保证字典序最小,肯定是位置越靠前越好,那么就可以这么构造序列。

对于不同的 k k k,在 k k k递增的过程中,序列是逐步构造的,所以我们可以对查询进行离线处理。

  • 将输入序列从大到小排序,并标记位置方便之后回找。
  • m m m次询问从短到长排序,长度相同 p o s pos pos越小越靠前,并标记位置。
  • 依次按数值大小,将数值放入树状数组中维护,维护的是当前放入数据在原数据的位置。
  • 对于所求第 p o s pos pos个数值,在满足放入 k k k个数字后,二分查找1~ n n n中上一步出现的数字出现个数,找到第 p o s pos pos个位置,得到对应原序列的位置,保存答案。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define db double
#define REP(i, lim) for(int i=0;i<lim;++i)
#define REPP(i, lim) for(int i=1;i<=lim;++i)
#define DEC(i, lim) for(int i=lim;i>=1;--i)
#define FOR(i,l,r)  for(int i=l;i<r;++i)
#define deBug cout<<"==================================="<<endl;
#define clr(s) memset(s, 0, sizeof(s))
#define lowclr(s) memset(s, -1, sizeof(s))
const int MAXN = 1000055;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;

int n, m;
int a[MAXN], c[MAXN], ans[MAXN];

struct Num{
    int val, index;
}num[MAXN];

bool cmpNum(Num A, Num B) {
    return A.val > B.val || (A.val == B.val && A.index < B.index);
}

struct Que{
    int k, pos, index;
}que[MAXN];

bool cmpQue(Que A, Que B) {
    return A.k < B.k || (A.k == B.k && A.pos < B.pos);
}

int lowbit(int x) { return x & -x; }

void update(int i, int v) {
    while(i<=n) {
        c[i] += v;
        i += lowbit(i);
    }
}

int getSum(int i) {
    int ans = 0;
    while(i>0) {
        ans += c[i];
        i -= lowbit(i);
    }
    return ans;
}


int main()
{
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);

    cin>>n;

    REPP(i, n) {
        cin>>a[i];
        num[i].val = a[i];
        num[i].index = i;
    }
    sort(num+1, num+n+1, cmpNum);

    cin>>m;
    REPP(i, m) {
        cin>>que[i].k>>que[i].pos;
        que[i].index = i;
    }
    sort(que+1, que+m+1, cmpQue);

    int len = 0;
    REPP(i, m) {
        while(len < que[i].k) {
            len++;
            update(num[len].index, 1);
        }
        int l = 1, r = n, mid;
        int tar = 0;
        while(l <= r) {
            mid = r + (l - r) / 2;
            int cnt = getSum(mid);
            if(cnt >= que[i].pos)   r = mid - 1, tar = mid;
            else                    l = mid + 1;
        }
        ans[que[i].index] = a[tar];
    }

    REPP(i, m) cout<<ans[i]<<'\n';

    return 0;
}

E. Arson In Berland Forest

F. Wrong Answer on test 233 (Hard Version)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值