Codeforces Round #223 (Div. 2) 题解
A.Sereja and Dima
题意:有一列数,有A,B两个人,每个人只会拿数组两侧中大的那个数,问这样拿完以后每个人的价值和分别为多少
思路:直接按题意模拟
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1007; int a[maxn]; int main() { int n; scanf("%d", &n); for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); } int cnt = 1; int i = 1, j = n; int ansx = 0, ansy = 0; while(cnt <= n){ if(a[i] <= a[j]){ if(cnt & 1) ansx +=a[j]; else ansy += a[j]; j--; } else { if(cnt & 1) ansx += a[i]; else ansy += a[i]; i++; } cnt++; } printf("%d %d\n",ansx,ansy); return 0; }
B. Sereja and Stairs
题意:给n个数,让你从中选出一些数,可以构造一个先严格上升,在严格下降的数列,是数列长度最长,打印数列
思路:把每个数都标记一下,从小到大打印一遍所有值,最大值,然后把剩下的数在打印一次,不打印最大值
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 +7; int stk[maxn]; int top; int mp[5005]; int main() { int n; scanf("%d", &n); map<int,int> mp; int maxe = -1; for(int i = 1; i <= n; i++) { int x; scanf("%d", &x); mp[x] ++; maxe = max(maxe , x); } for(int i = 1; i <= maxe; i++){ if(mp[i]){ stk[++top] = i; mp[i]--; } } for(int i = maxe - 1; i; i--) { if(mp[i]) { stk[++top] = i; } } printf("%d\n",top); for(int i = 1; i <= top; i++) { if(i > 1)printf(" "); printf("%d",stk[i]); } puts(""); return 0; }
C. Sereja and Prefixes
题意:有两种操作,第一种操作是在数组最后面加入x,第二种操作是把数组前L个复制x次,有m次询问,每次询问回答数组中第i个数是几
思路:1操作时直接插入到数组中,在插入2操作时,标记一下这个2操作,每个位置都记录插入了多少个数,如果询问的时候,二分答案,如果是1操作的数,直接打印插入的数,如果是2操作,就在此递归之前的区间,直到找到1操作
代码:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int maxn = 1e6 + 7; int a[maxn]; int kind[maxn],t[maxn]; LL len[maxn]; int n; int solve(LL x) { int id = lower_bound(len + 1, len + 1 + n, x) - len; // printf("test %d\n",id); if(kind[id] == 1){ return a[id]; } else { return solve((x - len[id - 1] - 1) % a[id] + 1); } } int main() { scanf("%d",&n); LL nowlen = 0; for(int i = 1; i <= n; i++) { int op, val; scanf("%d%d", &op, &val); if(op == 1) { kind[i] = 1; a[i] = val; len[i] = len[i - 1] + 1; } else{ int time; scanf("%d", &time); kind[i] = 2; t[i] = time; a[i] = val; len[i] = len[i - 1] + time * val; } } int m ; scanf("%d", &m); while(m--) { LL x; scanf("%lld", &x); printf("%d ",solve(x)); } return 0; }
D. Sereja and Tree
题意:给出n和m(7000),带表一个n层的树和m次操作,树的结构是二叉树,如果b的2的某个次方,那b就有2个儿子,不然只有一个儿子,每个节点由(a,b)组成,a表示的是层数,b表示的是该节点在这一层的位置,有两种操作,1:给出t,l,r, x,表示在第t层[l,r]节点上添加一个数x;2:给出a,b,要求计算节点(a,b)以及它所有的孩子节点中共有多少中数字(重复不算)。
思路:因为n和m都只有7000,所以直接n2暴力就可以出答案
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 7007; const int maxe = 200000; struct node { int l, r, val; }; vector<node>a[maxn]; int ll[maxe], rr[maxe]; set<int> mp; int main() { int n, m; scanf("%d%d", &n, &m); ll[1] = 1, rr[1] = 2; int now = 1, cnt = 3; ll[1] = 1; rr[1] = 2; for (int i = 2; i < maxe; i++) { if ((1 << now) == i) { now++; ll[i] = cnt++; } else ll[i] = -1; rr[i] = cnt++; } for(int i = 1; i <= m; i++) { int op; scanf("%d", &op); if(op == 1){ int t; node as; scanf("%d%d%d%d", &t, &as.l, &as.r, &as.val); a[t].push_back(as); } else { int L, R; scanf("%d%d", &L, &R); mp.clear(); int l = R, r = R; for(int j = L; j <= n; j++) { // printf("j == %d %d l==%d r==%d\n",j,a[j].size(),l,r); for(int k = 0; k < a[j].size(); k++) { // printf("aaa %d a[j][k].l==%d r==%d a[i].[\n",k); if(a[j][k].l <= r && a[j][k].r >= l)mp.insert(a[j][k].val); } l = (ll[l] == -1 ? rr[l] : ll[l]); r = rr[r]; } printf("%d\n",mp.size()); } } return 0; }
E. Sereja and Brackets
题意:给一段括号序列,有m次询问,每次回答[l,r]区间中有多少对括号匹配
思路:用线段树直接维护,每个节点分别记录l,r,m,表示剩余没有匹配的左括号数量,剩余没有匹配的有括号数量,已经匹配的括号数量
代码:
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 7; char a[maxn]; int numl[maxn<<2],numr[maxn<<2],numm[maxn<<2]; void pushup(int rt) { int minn = min(numl[rt << 1],numr[rt << 1 | 1]); numm[rt] = numm[rt << 1] + numm[rt << 1 | 1] + 2 * minn; numl[rt] = numl[rt << 1 | 1] + numl[rt << 1] - minn; numr[rt] = numr[rt << 1] + numr[rt << 1 | 1] - minn; } void build(int rt,int l,int r) { if(l == r){ if(a[l] == '(')numl[rt] = 1; else numr[rt] = 1; return ; } int mid = (l + r) >> 1; build(rt << 1, l, mid); build(rt << 1 | 1, mid + 1,r); pushup(rt); } struct node { int l,r,m; }; node query(int L,int R,int rt,int l,int r) { // if(l > r)return 0; if(L <= l && r <= R){ node as; as.l = numl[rt]; as.r = numr[rt]; as.m = numm[rt]; return as; } int mid = (l + r) >> 1; if(R <= mid) return query(L, R, rt << 1, l, mid); else if(L > mid) return query(L, R, rt << 1 | 1, mid + 1, r); else{ node as = query(L, R, rt << 1, l, mid); node qw = query(L, R, rt << 1 | 1, mid + 1, r); node ans; int minn = min(as.l, qw.r); ans.m = as.m + qw.m + 2 * minn; ans.l = as.l + qw.l - minn; ans.r = as.r + qw.r - minn; return ans; } } int main() { scanf("%s",a + 1); int n = strlen(a + 1); build(1, 1, n); int q; scanf("%d", &q); while(q--){ int l, r; scanf("%d%d", &l, &r); printf("%d\n",query(l,r,1,1,n).m); } return 0; }