Codeforces Round #590 (Div. 3)
A - Equalize Prices Again
题意:给n个商品,每个商品价格不同,要调整他们的价格,使得总价不下降且他们的价格相等,在此基础上最小化总价。
题解:找超过原总价的最小的n的倍数。
void test_case() {
int n;
scanf("%d", &n);
ll sum = 0;
for(int i = 1; i <= n; ++i) {
ll tmp;
scanf("%lld", &tmp);
sum += tmp;
}
sum = (sum + n - 1) / n;
printf("%lld\n", sum);
}
B1 - Social Network (easy version)
见下
B2 - Social Network (hard version)
题意:有个手机,屏幕能显示k个聊天窗口,已知n个人给你发消息的序列,求最终的聊天窗口。
调整规则如下:
- 假如当前聊天窗口中有这个人,啥都不做,结束
- 否则,若窗口已满,去掉最底部的窗口
- 其他窗口下移,新的显示在顶部
题解:看起来就是个队列,然后还要查队列里有没有某个元素,这个用个set就完事了。不过最后题目要从顶部到底部输出,所以一开始就用双端队列就很方便。
set<int> s;
deque<int> q;
void test_case() {
s.clear();
int n, k;
scanf("%d%d", &n, &k);
for(int i = 1; i <= n; ++i) {
int id;
scanf("%d", &id);
if(s.count(id))
continue;
else {
if(q.size() >= k) {
s.erase(q.front());
q.pop_front();
}
q.push_back(id);
s.insert(id);
}
}
printf("%d\n", (int)q.size());
while(q.size()) {
printf("%d ", q.back());
q.pop_back();
}
printf("\n");
}
C - Pipes
题意:有个两行的水管,水管只有两种形状,直的,或者拐角的。连接这些水管使得(1,0)的水可以流到(2,n+1)。
题解:由于只有两行,所以每行结束必须往右流,直接dp即可。注意设置的时候不要在同层之间传递。
char s[2][200005];
bool dp[2][200005];
void test_case() {
int n;
scanf("%d", &n);
scanf("%s%s", s[0] + 1, s[1] + 1);
for(int i = 1; i <= n; ++i)
s[0][i] -= '0', s[1][i] -= '0';
/*for(int i = 1; i <= n; ++i)
putchar(s[0][i]);
putchar('\n');
for(int i = 1; i <= n; ++i)
putchar(s[1][i]);
putchar('\n');*/
for(int i = 1; i <= n; ++i)
dp[0][i] = dp[1][i] = 0;
dp[0][0] = 1;
dp[1][0] = 0;
for(int i = 1; i <= n; ++i) {
if(dp[0][i - 1] == 1 && s[0][i] <= 2)
dp[0][i] = 1;
if(dp[1][i - 1] == 1 && s[1][i] <= 2)
dp[1][i] = 1;
if(dp[0][i - 1] == 1 && s[0][i] >= 3 && s[1][i] >= 3)
dp[1][i] = 1;
if(dp[1][i - 1] == 1 && s[1][i] >= 3 && s[0][i] >= 3)
dp[0][i] = 1;
}
/*for(int i = 0; i <= n; ++i)
printf("%d", (int)dp[0][i]);
putchar('\n');
for(int i = 0; i <= n; ++i)
printf("%d", (int)dp[1][i]);
putchar('\n');*/
if(dp[1][n])
puts("YES");
else
puts("NO");
}
D - Distinct Characters Queries
题意:给个只有小写拉丁字母的字符串,然后q次操作。
操作1:把pos位置换成小写拉丁字母c。(pos一定在原串中)
操作2:求[l,r]区间有多少种字母。
题解:线段树
struct SegmentTree {
#define ls (o<<1)
#define rs (o<<1|1)
static const int MAXN = 200000;
int a[MAXN + 5];
int st[(MAXN << 2) + 5];
void PushUp(int o) {
st[o] = st[ls] | st[rs];
}
void Build(int o, int l, int r) {
if(l == r)
st[o] = a[l];
else {
int m = l + r >> 1;
Build(ls, l, m);
Build(rs, m + 1, r);
PushUp(o);
}
}
void Update(int o, int l, int r, int p, int v) {
if(l == r) {
st[o] = v;
return;
} else {
int m = l + r >> 1;
if(p <= m)
Update(ls, l, m, p, v);
if(p >= m + 1)
Update(rs, m + 1, r, p, v);
PushUp(o);
}
}
int Query(int o, int l, int r, int ql, int qr) {
if(ql <= l && r <= qr) {
return st[o];
} else {
int m = l + r >> 1;
int res = 0;
if(ql <= m)
res = res | Query(ls, l, m, ql, qr);
if(qr >= m + 1)
res = res | Query(rs, m + 1, r, ql, qr);
return res;
}
}
#undef ls
#undef rs
} st;
char s[200005];
void test_case() {
scanf("%s", s + 1);
int n = strlen(s + 1);
for(int i = 1; i <= n; ++i)
st.a[i] = 1 << (s[i] - 'a');
st.Build(1, 1, n);
/*for(int i = 1; i <= n; ++i)
printf("%d ", st.Query(1, 1, n, i, i));
putchar('\n');*/
int q;
scanf("%d", &q);
while(q--) {
int op;
scanf("%d", &op);
if(op == 1) {
int x;
char ch[2];
scanf("%d%s", &x, ch);
st.Update(1, 1, n, x, 1 << (ch[0] - 'a'));
} else {
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", __builtin_popcount((uint)st.Query(1, 1, n, l, r)));
}
}
}
*E - Special Permutations
数字i在排列中的位置,总是(i-1)次i,1次1,n-i次i+1。相邻的两个排列最多改变了两个数的位置。