CSP-S模拟17
A. 最大匹配
这都可以排序……关于我把它画到了平面直角坐标系上怎么都想不出来这件事……
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 3;
const ll mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
int n;
ll ans;
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 << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
struct node
{
int a, b;
bool operator < (const node &T) const
{
return a+b > T.a+T.b;
}
}p[maxn];
int main()
{
n = read();
for(int i=1; i<=2*n; i++)
{
p[i].a = read(); p[i].b = read();
if(p[i].a < p[i].b) swap(p[i].a, p[i].b);
}
sort(p+1, p+1+2*n);
for(int i=1,j=2*n; i<=n; i++,j--)
{
ans += abs((ll)p[j].b-p[i].a);
}
printf("%lld\n", ans);
return 0;
}
B. 挑战ABC
先特判不用操作的情况。
只需要一次操作的条件是,只有一种字符小于n,假设它是A,如果可以找到一个区间[l,r]把它变成A之后B的个数和C的个数都恰好为n就可以。
剩下的都可以用两次操作解决,构造方法是找到一个最小的位置p,使[1,p]中出现最多的字符恰好出现了n次,假设为A,还需要n-cntb[1,p]个B就把之后的这一段变成B,最后一段变成C。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 3;
int n, m, c[3][maxn], p;
char pc, s[maxn];
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 << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
bool f1(char t)
{
int x = (t-'A'+1)%3, y = (t-'A'+2)%3;
for(int l=1,r=1; l<=m; l++)
{
if(r < l) r = l;
while((c[x][r]-c[x][l-1] < c[x][m]-n || c[y][r]-c[y][l-1] < c[y][m]-n) && r <= m) r++;
if(c[x][r]-c[x][l-1] == c[x][m]-n && c[y][r]-c[y][l-1] == c[y][m]-n)
{
printf("1\n%d %d %c\n", l, r, t); return 1;
}
}
return 0;
}
void f2()
{
printf("2\n");
int x = (pc-'A'+1)%3, y = (pc-'A'+2)%3;
char X = x + 'A', Y = y + 'A';
printf("%d %d %c\n", p+1, p+n-c[x][p], X);
printf("%d %d %c\n", p+n-c[x][p]+1, m, Y);
}
int main()
{
n = read(); m = n*3;
scanf("%s", s+1);
for(int i=1; i<=m; i++)
{
for(int j=0; j<3; j++)
{
c[j][i] = c[j][i-1];
}
c[s[i]-'A'][i]++;
if(!p && c[s[i]-'A'][i] == n) p = i, pc = s[i];
}
if(c[0][m] == c[1][m] && c[1][m] == c[2][m])
{
printf("0\n"); exit(0);
}
if(f1('A') || f1('B') || f1('C')) exit(0);
f2();
return 0;
}
C. 三级跳
原题是JOI open 2019,可以在LOJ 3153找到(我好像刚才不小心写成了3193**),同时还来自上一届省选模拟31(3.14),T2法阵。
枚举前两个数,符合要求的前两个数中间不能有比这两个数大的数,如果有的话,这个数比原来的那两个优秀,用vector记录一下这些数对,然后用线段树维护原数组的区间最大值和实时更新的最大答案。
有效的(x, y)必然在从左到右单调栈时相遇(y弹掉x或y压在x的后面),这样的(x, y)只有O(n)对。
如果有的起点和中转点对应的最小的最后一个点大于n,就导致线段树更新时L > R。我本来以为多更新了不存在的答案至少应该变多,但是它变少了(样例1的第2个询问输出8本来是9),因为对于一个不合法的区间,L <= l && r <= R永远不可能满足条件即使是叶子,所以这个叶子就会被它不存在的孩子pushup,然后他的mx就变成了0!!!
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 3;
int n, a[maxn], Q, stk[maxn], top;
ll ans[maxn];
vector<int> vec[maxn];
struct que
{
int l, r, id;
bool operator < (const que &T) const
{
return l < T.l;
}
}q[maxn];
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 << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
struct tree
{
struct node
{
ll mx, ms, tag;
}t[maxn<<2];
void pushup(int x)
{
t[x].mx = max(t[x<<1].mx, t[x<<1|1].mx);
t[x].ms = max(t[x<<1].ms, t[x<<1|1].ms);
}
void pushdown(int x)
{
int ls = x << 1, rs = x << 1 | 1;
t[ls].ms = max(t[ls].ms, t[ls].mx+t[x].tag);
t[ls].tag = max(t[ls].tag, t[x].tag);
t[rs].ms = max(t[rs].ms, t[rs].mx+t[x].tag);
t[rs].tag = max(t[rs].tag, t[x].tag);
t[x].tag = 0;
}
void build(int x, int l, int r)
{
if(l == r)
{
t[x].ms = t[x].mx = a[l]; return;
}
int mid = (l + r) >> 1;
build(x<<1, l, mid);
build(x<<1|1, mid+1, r);
pushup(x);
}
void update(int x, int l, int r, int L, int R, ll val)
{
if(L > R) return;
if(L <= l && r <= R)
{
t[x].ms = max(t[x].ms, t[x].mx+val);
t[x].tag = max(t[x].tag, val);
return;
}
int mid = (l + r) >> 1;
if(t[x].tag) pushdown(x);
if(L <= mid) update(x<<1, l, mid, L, R, val);
if(R > mid) update(x<<1|1, mid+1, r, L, R, val);
pushup(x);
}
ll query(int x, int l, int r, int L, int R)
{
if(L <= l && r <= R) return t[x].ms;
int mid = (l + r) >> 1; ll ans = 0;
if(t[x].tag) pushdown(x);
if(L <= mid) ans = max(ans, query(x<<1, l, mid, L, R));
if(R > mid) ans = max(ans, query(x<<1|1, mid+1, r, L, R));
return ans;
}
}t;
int main()
{
n = read();
for(int i=1; i<=n; i++)
{
a[i] = read();
while(top && a[stk[top]] <= a[i])
{
vec[stk[top]].push_back(i); top--;
}
if(top) vec[stk[top]].push_back(i);
stk[++top] = i;
}
t.build(1, 1, n);
Q = read();
for(int i=1; i<=Q; i++)
{
q[i].l = read(); q[i].r = read(); q[i].id = i;
}
sort(q+1, q+1+Q); q[Q+1].l = n+1;
for(int i=Q; i>=1; i--)
{
if(q[i].l < q[i+1].l)
{
for(int j=q[i+1].l-1; j>=q[i].l; j--)
{
for(int k : vec[j])
{
t.update(1, 1, n, k-j+k, n, a[j]+a[k]);
}
}
}
ans[q[i].id] = t.query(1, 1, n, q[i].l, q[i].r);
}
for(int i=1; i<=Q; i++)
{
printf("%lld\n", ans[i]);
}
return 0;
}
D. 经典线性基
(⊙o⊙)…
时光花火,水月星辰