欢迎进入博客浏览
>>我的博客<<
更好的排版,更好的阅读体验
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 b−a 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 k−1种。
既满足以下形式的序列可行:
(
)
(
)
(
(
(
(
(
)
)
)
)
)
()()((((()))))
()()((((()))))
数据不大,暴力构造就可以。
代码:
#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;
}