jusge: CodeForces
题解的分析顺序采用倒叙。
D. Program
judge: CodeForces
题意
给你一个初始值为 0 0 0 的 x x x,和由若干个+
和-
组成的序列,+
代表下一轮 x x x 的值+1,-
代表下一轮 x x x 的值-1。
有 m m m 次操作,每次操作给出一段区间 [ l , r ] [l,r] [l,r],求出忽略 [ l , r ] [l,r] [l,r] 区间的序列执行过程中 x x x 的不同状态的数量。
例如当序列为--+
时, x x x 的取值是0,-1,-2,-1
,一共有 3 3 3 种状态。
题解
当一段操作确定时,求出状态数并不难。只需要找出所有状态的最大值减去最小值再加一即可。
问题在于当忽略中间的某一段操作时,后面的状态就不确定了。
定义 x [ 0 ] = 0 x[0]=0 x[0]=0,代表初始状态, x [ 1 ] x[1] x[1] 为第一个操作完成后的 x x x 的状态,剩下的依次递推。
维护 x x x 上的区间最大值和最小值,当忽略区间为 [ l , r ] [l,r] [l,r] 的操作时(为了简化,我们假设 l > 1 l>1 l>1 且 r < n r<n r<n),求出 [ 0 , l − 1 ] [0,l-1] [0,l−1] 的最大值,最小值分别为 l m a , l m i lma,lmi lma,lmi; [ r , n ] [r,n] [r,n]的最大值,最小值分别为 r m a , r m i rma,rmi rma,rmi。注意所求的最值的区间需要包含它的前一个状态,因为状态数计数时是考虑 x x x 的前一个状态的,所以计算的区间分别是从 0 0 0 和 r r r 开始,而不是 1 1 1 和 r + 1 r+1 r+1。
由于中间忽略了一部分操作,后面计算得来的状态的最值不可信。要保持状态同步需要让
r m a = r m a − x [ r ] + x [ l − 1 ] rma=rma-x[r]+x[l-1] rma=rma−x[r]+x[l−1]
r m i = r m i − x [ r ] + x [ l − 1 ] rmi=rmi-x[r]+x[l-1] rmi=rmi−x[r]+x[l−1]
这样就求出全部操作的执行过程中 x x x 的最大值和最小值了。
那么 x x x 的不同状态的数量无非就是 l m a − l m i + 1 lma-lmi+1 lma−lmi+1, l m a − r m i + 1 lma-rmi+1 lma−rmi+1, r m a − r m i + 1 rma-rmi+1 rma−rmi+1, r m a − l m i + 1 rma-lmi+1 rma−lmi+1中的最大值。
考虑到线段树维护的区间是从 1 1 1 开始的,所以我们把维护的区间整体右移一位,也就是定义 x [ 1 ] = 0 x[1]=0 x[1]=0,代表初始值, x [ 2 ] x[2] x[2] 为第一个操作完成后的 x x x 的状态,剩下的以此递推。
代码
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
// #define max(a, b) ((a) > (b) ? (a) : (b))
// #define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 200005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') {
if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') {
x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
struct poi {
};
int n, m;
char s[maxn];
int a[maxn];
int ma[maxn << 2], mi[maxn << 2];
void build(LL node, LL beg, LL end) {
if (beg == end) {
ma[node] = a[beg];
mi[node] = a[beg];
return;
}
LL mid = (beg + end) >> 1;
build(node << 1, beg, mid);
build(node << 1 | 1, mid + 1, end);
ma[node] = max(ma[node << 1], ma[node << 1 | 1]);
mi[node] = min(mi[node << 1], mi[node << 1 | 1]);
}
LL queryMax(LL node, LL beg, LL end, LL l, LL r) {
if (l <= beg && r >= end) return ma[node];
LL ans = -inf;
LL mid = (beg + end) >> 1;
if(mid >= l) ans = max(ans, queryMax(node << 1, beg, mid, l, r));
if(mid < r) ans = max(ans, queryMax(node << 1 | 1, mid + 1, end, l, r));
return ans;
}
LL queryMin(LL node, LL beg, LL end, LL l, LL r) {
if (l <= beg && r >= end) return mi[node];
LL ans = inf;
LL mid = (beg + end) >> 1;
if(mid >= l) ans = min(ans, queryMin(node << 1, beg, mid, l, r));
if(mid < r) ans = min(ans, queryMin(node << 1 | 1, mid + 1, end, l, r));
return ans;
}
void init() {
}
void sol() {
init();
scanf("%s", s + 1);
int x = 0;
_rep(i, 1, n) {
if(s[i] == '-') a[i + 1] = --x;
else a[i + 1] = ++x;
}
build(1, 1, n + 1);
_for(i, m) {
int ans = 1;
int l = read(), r = read();
l = max(1, l);
r = min(r, n);
if(l > 1 && r < n) {
int lma = queryMax(1, 1, n + 1, 1, l);
int lmi = queryMin(1, 1, n + 1, 1, l);
int rma = queryMax(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
int rmi = queryMin(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
ans = max(ans, lma - lmi + 1);
ans = max(ans, rma - rmi + 1);
ans = max(ans, lma - rmi + 1);
ans = max(ans, rma - lmi + 1);
}
else if(l > 1) {
int lma = queryMax(1, 1, n + 1, 1, l);
int lmi = queryMin(1, 1, n + 1, 1, l);
ans = max(ans, lma - lmi + 1);
}
else if(r < n) {
int rma = queryMax(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
int rmi = queryMin(1, 1, n + 1, r + 1, n + 1) - a[r + 1] + a[l];
ans = max(ans, rma - rmi + 1);
}
printf("%d\n", ans);
}
}
int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// debug = 1;
#endif
time_t beg, end;
if(debug) beg = clock();
int T = read();
_for(i, T) {
n = read(), m = read();
sol();
}
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
return 0;
}
C. No More Inversions
judge: CodeForces
题意
给你两个整数 n n n 和 k k k,可以唯一确定一个序列a:
1,2,3,…,k−1,k,k−1,k−2,…,k−(n−k)
( k ≤ n < 2 k ) (k≤n<2k) (k≤n<2k)
让你找出一个排列 p p p,并且序列 b [ i ] = p [ a [ i ] ] b[i]=p[a[i]] b[i]=p[a[i]],使 b b b 的逆序数不大于 a a a 的逆序数,且 b b b 的字典序最大。
题解
找规律发现,当我们交换 p p p 中 [ 2 k − n , k ] [2k-n,k] [2k−n,k] 中的两个数字时,逆序数不变。
例如1 2 3 2
的逆序数为 1 1 1,交换 2 2 2 和 3 3 3 后序列变成1 3 2 3
,逆序数依然是 1 1 1.
再比如1 2 3 4 3 2
的逆序数为 4 4 4,交换 2 2 2 和 4 4 4 后序列变成1 4 3 2 3 4
,逆序数依然是 4 4 4。
要使字典序最大,需要把较大的数尽可能移到前面,所以我们使序列变成 1,2,...,2k-n,k,k-1,...,2k-n+1,2k-n,2k-n+1,...,k-1,k
( k ≤ n < 2 k ) (k≤n<2k) (k≤n<2k)。
例如1,2,3,4,5,4,3
变成1,2,5,4,3,4,5
。
剩下的就是编码问题,这里不再赘述。
代码
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 200005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') {
if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') {
x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
struct poi {
};
int n, k;
int a[maxn];
int p[maxn];
void init() {
}
void sol() {
init();
n = read(), k = read();
if(n == 1) {
printf("1\n");
return;
}
if(n == k) {
_rep(i, 1, n) printf("%d%s", i, nl(i, n + 1));
return;
}
_rep(i, 1, k) a[i] = i;
_rep(i, 1, n - k) a[k + i] = k - i;
_rep(i, 1, k) p[i] = i;
for(int i = 1; i <= n - k + 1; ++i) p[2 * k - n + i - 1] = k - i + 1;
_rep(i, 1, k) printf("%d%s", p[i], nl(i, k + 1));
}
int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
// debug = 1;
#endif
time_t beg, end;
if(debug) beg = clock();
int T = read();
_for(i, T) {
sol();
}
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
return 0;
}
B. String LCM
judge: CodeForces
题意
定义一种性质,如果有一个字符串 l l l,满足 l l l 是由若干次字符串 s s s 拼接而成,且满足 l l l 是由若干次 t t t 拼接而成,满足此条件的最短的 l l l 称为 s s s 和 t t t 的“LCM”。
有两个字符串 s s s 和 t t t,判断他们是否存在“LCM”,若存在就输出他们的“LCM”,否则输出-1
。
题解
定义 l s ls ls 为 s s s 的长度, l t lt lt 为 t t t 的长度。
由于“LCM”唯一,所以“LCM”的长度一定是 n = l s × l t × g c d ( l s , l t ) n=ls\times lt\times gcd(ls,lt) n=ls×lt×gcd(ls,lt)。
重复 n / l s n/ls n/ls 次 s s s 串,再将之与重复 n / l t n/lt n/lt 次的 t t t 串作比较,若完全相同则说明存在“LCM”,且“LCM”就是长度为 n n n 的串。否则就不存在“LCM”。
代码
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 100005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') {
if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') {
x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
struct poi {
};
char s[maxn], t[maxn], tar[maxn];
void init() {
}
int sol() {
init();
scanf("%s%s", s, t);
int ls = strlen(s), lt = strlen(t);
int n = ls / __gcd(ls, lt) * lt;
_for(i, n / ls) _for(j, ls) tar[i * ls + j] = s[j];
_for(i, n / lt) _for(j, lt) if(tar[i * lt + j] != t[j]) return -1;
tar[n] = 0;
printf("%s\n", tar);
return 1;
}
int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
debug = 1;
#endif
time_t beg, end;
if(debug) beg = clock();
int T = read();
_for(i, T) {
if(sol() == -1) printf("-1\n");
}
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
return 0;
}
A. Replacing Elements
judge: CodeForces
题意
定义一种操作:选择三个不同的下标使得 a [ i ] = a [ j ] + a [ k ] a[i]=a[j]+a[k] a[i]=a[j]+a[k]。
你可以执行此操作任意次。
回答是否可以通过若干次此操作使数列的任何一个数字都小于等于 m m m。
题解
首先检查一下数列里是否有大于 m m m 的数字,如果没有那就什么都不用做就能满足要求。
其次检查最小的两个数的和是否小于等于 m m m。如果小于等于 m m m,那么我就可以把其余的所有数字都变成这两个数字的和,这样所有的数字就都小于等于 m m m 了。否则就是不可能使所有的数字都小于等于 m m m。
代码
#pragma GCC optimize(2)
#include <bits/stdc++.h>
#define m_p make_pair
#define p_i pair<int, int>
#define _for(i, a) for(register int i = 0, lennn = (a); i < lennn; ++i)
#define _rep(i, a, b) for(register int i = (a), lennn = (b); i <= lennn; ++i)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n"
#define mem(a, b) memset(a, b, sizeof(a))
#define mem0(a) memset(a, 0, sizeof(a))
#define fil(a, b) fill(a.begin(), a.end(), b);
#define scl(x) scanf("%lld", &x)
#define sc(x) scanf("%d", &x)
#define pf(x) printf("%d\n", x)
#define pfl(x) printf("%lld\n", x)
#define abs(x) ((x) > 0 ? (x) : -(x))
#define PI acos(-1)
#define lowbit(x) (x & (-x))
#define dg if(debug)
#define nl(i, n) (i == n - 1 ? "\n":" ")
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
typedef long long LL;
// typedef __int128 LL;
typedef unsigned long long ULL;
const int maxn = 100005;
const int maxm = 1000005;
const int maxp = 30;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const int mod = 1000000007;
const double eps = 1e-8;
const double e = 2.718281828;
int debug = 0;
inline int read() {
int x(0), f(1); char ch(getchar());
while (ch<'0' || ch>'9') {
if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0'&&ch <= '9') {
x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
struct poi {
};
int a[maxn];
void init() {
}
void sol() {
init();
int n = read(), m = read();
int mi = inf, sec = inf;
int f = 1;
_for(i, n) {
a[i] = read();
if(a[i] > m) f = 0;
}
if(f) {
printf("YES\n");
return;
}
_for(i, n) {
if(a[i] < mi) sec = mi, mi = a[i];
else if(a[i] < sec) sec = a[i];
}
printf("%s\n", mi + sec <= m ? "YES":"NO");
}
int main() {
//ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
debug = 1;
#endif
time_t beg, end;
if(debug) beg = clock();
int T = read();
_for(i, T) {
sol();
}
if(debug) {
end = clock();
printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
}
return 0;
}