Codeforces Round #466 (Div. 2) 题解

A.Points on the line

题目大意:

给你一个数列,定义数列的权值为最大值减去最小值,问最少删除几个数,使得数列的权值小于等于给定值d

题解:

排序,每次挑最大的和最小的,看看最小的能跟多少个数差\(>d\),看看最大的能跟多少个数差\(>d\),取个数大的那个删除。复杂度\(n^2 + n\log n\)

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void swap(T &x, T &y)
{
T tmp = x;x = y, y = tmp;
}
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 100 + 10; int n,d,num[MAXN]; int main()
{
// freopen("data.txt", "r", stdin);
read(n), read(d);
for(int i = 1;i <= n;++ i) read(num[i]);
std::sort(num + 1, num + 1 + n);
int l = 1, r = n, ans = 0;
while(l <= r)
{
int tmp1 = r, tmp2;
while(num[tmp1] - num[l] > d) -- tmp1;
tmp2 = r - tmp1; int tmp3 = l, tmp4;
while(num[r] - num[tmp3] > d) ++ tmp3;
tmp4 = tmp3 - l; if(tmp2 == 0 && tmp4 == 0) break;
if(tmp2 >= tmp4) ++ l;
else -- r;
++ ans;
}
printf("%d", ans);
return 0;
}

B.Our Tanya is Crying Out Loud

题目大意:

给你一个数\(n\),可以对它指向两种操作。第一种操作令\(n\)减去\(1\),花费\(A\);第二种操作,当且仅当\(n\)为\(k\)的倍数时可以执行,使得\(n /= k\),花费\(B\),求让\(n\)变为\(1\)的最小花费

题解:

直接模拟即可,如果不是\(k\)的倍数就暴力减到\(k\)的倍数;如果是\(k\)的倍数,看是\(\div k\)优还是一步一步\(-1\)到\(\frac{n}{k}\)优即可。复杂度\(\log_kn\),注意特判\(k = 1\)的情况。因为脑残\(fst\)掉了。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void swap(T &x, T &y)
{
T tmp = x;x = y, y = tmp;
}
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const long long INF = 0x3f3f3f3f; long long n,k,a,b; int main()
{
// freopen("data.txt", "r", stdin);
read(n), read(k), read(a), read(b);
if(k == 1) printf("%I64d", (n - 1) * a);
else
{
long long ans = 0;
while(n > 1)
{
if(n % k == 0)
{
if(b < (n - n/k) * a) ans += b, n /= k;
else ans += (n - n/k) * a, n /= k;
}
else
{
if(n - n%k > 1) ans += a * (n%k), n -= n%k;
else ans += a * (n % k - 1), n = 1;
}
}
printf("%I64d", ans);
}
return 0;
}

C. Phone Numbers

题目大意:

给你一个长度为\(n\)字符串,要求你用字符串里的字符拼凑出一个字典序最小的比该字符串字典序大的长度为\(k\)字符串

题解:

贪心即可。若\(n < k\),直接输出原串,并在末尾加字典序最小的字符;若\(n>=k\),从给的字符串第\(k\)位往前扫,尝试某一位换位字典序比他大的字符里字典序最小的哪一个,如果能换,那么就换掉,后面的用字典序最小的字符填满\(k\)位,就是答案

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void swap(T &x, T &y)
{
T tmp = x;x = y, y = tmp;
}
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const int INF = 0x3f3f3f3f;
const int MAXN = 100000 + 10; char s[MAXN];
int n,k; int a[30],tot,b[30], nxt[30]; int main()
{
// freopen("data.txt", "r", stdin);
read(n), read(k);
scanf("%s", s + 1);
for(int i = 1;i <= n;++ i)
if(!b[s[i] - 'a' + 1])
b[s[i] - 'a' + 1] = ++ tot, a[tot] = s[i] - 'a' + 1;
std::sort(a + 1, a + 1 + tot);
for(int i = 1;i <= tot;++ i)
nxt[a[i]] = a[i + 1];
if(k <= n)
{
for(int i = k;i >= 1;-- i)
{
if(nxt[s[i] - 'a' + 1])
{
for(int j = 1;j < i;++ j) printf("%c", s[j]);
printf("%c", nxt[s[i] - 'a' + 1] + 'a' - 1);
for(int j = i + 1;j <= k;++ j) printf("%c", a[1] + 'a' - 1);
return 0;
}
}
}
else
{
printf("%s", s + 1);
for(int i = n + 1;i <= k;++ i) printf("%c", a[1] + 'a' - 1);
}
return 0;
}

D. Alena And The Heater

题目大意:

给你两个长度均为\(n\)的数列\(a\)和\(b\),要求找到任意一组\(l\),\(r\),对于任意\(5 <= i <= n\),满足:

\(b_i = 0\),如果\(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} > r\)并且\(b_{i-1}=b_{i-2}=b_{i-3}=b_{i-4}=1\)

\(b_i = 1\),如果\(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} < l\)并且\(b_{i-1}=b_{i-2}=b_{i-3}=b_{i-4}=0\)

其余情况\(b_i = b_{i-1}\)

题解:

如果\(b_{i-1}=b_{i-2}=b_{i-3}=b_{i-4}=1\)

如果\(b_i = 0\) 那么 \(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} > r\)

如果\(b_i = 1\) 那么 \(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} \leq\ r\)

如果\(b_{i-1} = b_{i-2} = b_{i-3} = b_{i-4} = 0\)

如果\(b_i = 0\) 那么 \(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} \geq\  r\)

如果\(b_i = 1\) 那么 \(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} < l\)

于是可以把l = -INF,r = INF,往里缩小,由于答案一定存在,我们只需让\(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} > r\)的条件令\(r = min(a_i + 1, a_{i-1} + 1, a_{i-2} + 1, a_{i-3} + 1, a_{i-4} + 1)\),即满足条件的最小值,这样由于答案存在,也就一定能满足所有的\(b_i = 1\) 那么 \(a_i, a_{i-1}, a_{i-2}, a_{i-3}, a_{i-4} \leq\ r\)。l同理。

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void swap(T &x, T &y)
{
T tmp = x;x = y, y = tmp;
}
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const long long INF = 1000000000;
const long long MAXN = 1000000 + 10;
/*
如果bi-1 = bi-2 = bi-3 = bi-4 = 1
如果bi = 0 那么 ai,ai-1,ai-2,ai-3,ai-4 > r
如果bi = 1 那么 ai,ai-1,ai-2,ai-3,ai-4 <= r
如果bi-1 = bi-2 = bi-3 = bi-4 = 0
如果bi = 0 那么 ai,ai-1,ai-2,ai-3,ai-4 >= l
如果bi = 1 那么 ai,ai-1,ai-2,ai-3,ai-4 < l
*/
long long l = - INF, r = INF, n, a[MAXN], b[MAXN];
char s[MAXN];
int main()
{
freopen("data.txt", "r", stdin);
read(n);
for(long long i = 1;i <= n;++ i) read(a[i]);
scanf("%s", s + 1);
for(long long i = 1;i <= n;++ i) b[i] = s[i] - '0';
for(long long i = 5;i <= n;++ i)
{
if(b[i - 1] && b[i - 2] && b[i - 3] && b[i - 4])
{
if(!b[i])
r = min(r, min(a[i - 1] - 1, min(a[i - 2] - 1, min(a[i - 3] - 1, min(a[i - 4] - 1, a[i] - 1)))));
}
else if(!b[i - 1] && !b[i - 2] && !b[i - 3] && !b[i - 4])
{
if(b[i])
l = max(l, max(a[i - 1] + 1, max(a[i - 2] + 1, max(a[i - 3] + 1, max(a[i - 4] + 1, a[i] + 1)))));
}
}
printf("%I64d %I64d\n", l, r);
return 0;
}

E

题目大意:

给你一个数列和正数\(c\),你可以把它分成很多段,每个长度为\(l\)的段将会删除前\(\lfloor\frac{l}{c}\rfloor\)小的数,求一种划分,使得划分并删除数字后剩余数字的和最小。

题解:

首先是一个显而易见的套路\(DP\).

\(dp[i]\)表示到i的最小和,\(dp[i] = min(dp[i], dp[i - k] + calc(i - k + 1, i))\);

\(calc(l,r)\)表示\([l,r]\)单独分为一段,删除数后的和

然后就GG了。

想了两分钟想不动了,翻了翻别人的代码。。

cnm。。。

早知道再想想了。。。

首先考虑一个最优解,每一个最优解中\(kc + r\),\(k \geq 1\), \(1 \leq r < c\)长度的区间,等价于划分为一个\(kc\)长度的区间和一个\(r\)长度的区间。因为对于区间\([l, l + kc + r - 1]\),前\(k\)小的数一定在区间\([l, l + kc - 1]\)中。

为什么?反证法即可。如果有被删除的数存在于后面的区间\([l + kc, l + kc + r - 1]\)中,那么把区间\([l, l + kc + r - 1 ]\)重新划分成\([l, l + kc - 1]\)和\([l + kc, l + kc + r - 1]\),不会选\([l + kc, l + kc + r - 1]\)中原来被删除的数,而会删除\([l, l + kc - 1]\)中比原来被删除的数更大的数,答案更优。

接下来考虑每一个\(kc\),\(k > 1\)的区间

把它分为\(k\)个长度为\(c\)的区间,会发现每个区间都有一个在大区间里被删除的数,而且这个数也是小区间内该被删除的数

为什么?反证法即可,跟上面思路类似。如果大区间选的两个数在同一个长度为\(c\)的小区间里,鸽巢原理会导致一个区间空着,空着的那个区间删的数肯定比小区间的数大(否则就会被在大区间里被选了),那这种划分显然不是最优的。

于是可以发现,只需要\(c\)长度的区间就行了!问题转化为从一个数列里选一些长度为\(c\)的小区间,删掉里面最小的数。\(DP\)方程可以这样写:

\(dp[i] = min(dp[i - 1], dp[i - c] + sum[i] - sum[i - c] - min(i - c + 1, i))\)

\(min(i - c + 1, i)\)表示区间\([i - c + 1, i]\)的最小值

sgt或st表或单调队列维护即可

但是为了方便,我代码里的\(dp\)不是这么写的。。

\(dp[i]\)表示到i为止的最优化分,删除的数字的最大和

\(dp[i] = max(dp[i-1], di[i-c] + min(i - c + 1, i))\)

最后用总和减去即可

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
//#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
inline long long min(long long a, long long b)
{
return a < b ? a : b;
}
template <class T>
inline void swap(T &x, T &y)
{
T tmp = x;x = y, y = tmp;
}
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
}
const long long INF = 0x3f3f3f3f3f3f3f3f;
const long long MAXN = 400000 + 10; long long mi[MAXN << 2], n, c, a[MAXN], dp[MAXN], sum, ans;
void build(long long o = 1, long long l = 1, long long r = n)
{
if(l == r)
{
mi[o] = a[l];return;
}
long long mid = (l + r) >> 1;
build(o << 1, l, mid);
build(o << 1 | 1, mid + 1, r);
mi[o] = min(mi[o << 1], mi[o << 1 | 1]);
}
long long ask(long long ll, long long rr, long long o = 1, long long l = 1, long long r = n)
{
if(ll <= l && rr >= r) return mi[o];
long long mid = (l + r) >> 1, re = INF;
if(mid >= ll) re = ask(ll, rr, o << 1, l, mid);
if(mid < rr) re = min(re, ask(ll, rr, o << 1 | 1, mid + 1, r));
return re;
}
int main()
{
//freopen("data.txt", "r", stdin);
read(n), read(c);
for(long long i = 1;i <= n;++ i) read(a[i]), sum += a[i];
build(1,1,n);
for(long long i = c;i <= n;++ i)
dp[i] = max(dp[i - 1], dp[i - c] + ask(i - c + 1, i,1,1,n)), ans = max(ans, dp[i]);
printf("%I64d", sum - ans);
return 0;
}

F

题目大意:

给你一串序列,支持两种操作:

1:询问一段区间\([l,r]\)中数字出现次数的mex;

2:单点修改

题解:

带修改的莫队,敢打就能A。网上很多求mex的方法是把次数分块,但我发现有人暴力扫一遍求mex也能A,于是我就暴力扫了,居然没被卡。由于忘记给处理last的t赋初值,WA了一上午。。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <cmath>
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define abs(x) ((x) < 0 ? -1 * (x) : (x))
template <class T>
inline void read(T &x)
{
x = 0;char ch = getchar(), c = ch;
while(ch < '0' || ch > '9') c = ch, ch = getchar();
while(ch <= '9' && ch >= '0') x = x * 10 + ch - '0', ch = getchar();
if(c == '-') x = -x;
} const long long INF = 0x3f3f3f3f;
const long long MAXN = 2000000 + 10; long long n,q,size,num[MAXN],tmp[MAXN],ci[MAXN],cnt[MAXN],a[MAXN],tot,qtot,ctot,val[MAXN],p[MAXN],c[MAXN],last[MAXN],t[MAXN],pos[MAXN],tong[MAXN];
bool cmp1(long long a, long long b)
{
return tmp[a] < tmp[b];
}
struct Node
{
long long l, r, t, rank;
}node[MAXN];
bool cmp2(Node a, Node b)
{
return pos[a.l] == pos[b.l] ? (pos[a.r] == pos[b.r] ? a.t < b.t : pos[a.r] < pos[b.r]) : pos[a.l] < pos[b.l];
} long long l = 1, r = 0, ans, now = 0;
void add(long long x)
{
-- tong[ci[x]];
++ ci[x];
++ tong[ci[x]];
}
void del(long long x)
{
-- tong[ci[x]];
--ci[x];
++ tong[ci[x]];
}
void change(long long p, long long c)
{
if(l <= p && p <= r) del(num[p]), add(c);
num[p] = c;
} int main()
{
read(n), read(q);
for(long long i = 1;i <= n;++ i) read(num[i]), tmp[i] = num[i], cnt[i] = i;
for(long long i = 1;i <= q;++ i)
{
long long tmp;read(tmp);
if(tmp == 1)
{
++ qtot;read(node[qtot].l), read(node[qtot].r);
node[qtot].t = ctot, node[qtot].rank = qtot;
}
else
{
++ ctot, read(p[ctot]), read(c[ctot]);
num[n + ctot] = ::tmp[n + ctot] = c[ctot], cnt[n + ctot] = n + ctot;
}
}
std::sort(cnt + 1, cnt + 1 + n + ctot, cmp1);
tmp[0] = -1;
for(long long i = 1;i <= n + ctot;++ i)
{
if(tmp[cnt[i]] != tmp[cnt[i - 1]])
++ tot, val[tot] = tmp[cnt[i]];
num[cnt[i]] = tot;
t[cnt[i]] = tot;
} for(long long i = 1;i <= ctot;++ i)
c[i] = num[n + i], last[i] = t[p[i]], t[p[i]] = c[i]; size = pow(n, 0.666667);
for(long long i = 1;i <= n;++ i)
if((i - 1) % size == 0) pos[i] = pos[i - 1] + 1;
else pos[i] = pos[i - 1];
std::sort(node + 1, node + 1 + qtot, cmp2);
tong[0] = 1000000000;
for(long long i = 1;i <= qtot;++ i)
{
while(now < node[i].t) ++ now, change(p[now], c[now]);
while(now > node[i].t) change(p[now], last[now]), -- now;
while(r < node[i].r) ++ r, add(num[r]);
while(r > node[i].r) del(num[r]), -- r;
while(l < node[i].l) del(num[l]), ++ l;
while(l > node[i].l) -- l, add(num[l]);
ans = 0;
while(tong[ans]) ++ ans;
a[node[i].rank] = ans;
}
for(long long i = 1;i <= qtot;++ i) printf("%I64d\n", a[i]);
return 0;
}

Codeforces Round #466 (Div. 2) 题解940A 940B 940C 940D 940E 940F的更多相关文章

  1. Codeforces Round #466 (Div. 2) 题解

    人生中第三次\(CF\)... 考试中切了\(A\)~\(E\) \(F\)题会做没时间写 题解 A:Points on the line 题意 给定一个数列,删最小的数,使最大差不大于一个定值 So ...

  2. Codeforces Round #182 (Div. 1)题解【ABCD】

    Codeforces Round #182 (Div. 1)题解 A题:Yaroslav and Sequence1 题意: 给你\(2*n+1\)个元素,你每次可以进行无数种操作,每次操作必须选择其 ...

  3. Codeforces Round #466 (Div. 2) E. Cashback

    Codeforces Round #466 (Div. 2) E. Cashback(dp + 贪心) 题意: 给一个长度为\(n\)的序列\(a_i\),给出一个整数\(c\) 定义序列中一段长度为 ...

  4. Codeforces Round #608 (Div. 2) 题解

    目录 Codeforces Round #608 (Div. 2) 题解 前言 A. Suits 题意 做法 程序 B. Blocks 题意 做法 程序 C. Shawarma Tent 题意 做法 ...

  5. Codeforces Round #525 (Div. 2)题解

    Codeforces Round #525 (Div. 2)题解 题解 CF1088A [Ehab and another construction problem] 依据题意枚举即可 # inclu ...

  6. Codeforces Round #528 (Div. 2)题解

    Codeforces Round #528 (Div. 2)题解 A. Right-Left Cipher 很明显这道题按题意逆序解码即可 Code: # include <bits/stdc+ ...

  7. Codeforces Round #677 (Div. 3) 题解

    Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...

  8. Codeforces Round #665 (Div. 2) 题解

    Codeforces Round #665 (Div. 2) 题解 写得有点晚了,估计都官方题解看完切掉了,没人看我的了qaq. 目录 Codeforces Round #665 (Div. 2) 题 ...

  9. Codeforces Round #160 (Div. 1) 题解【ABCD】

    Codeforces Round #160 (Div. 1) A - Maxim and Discounts 题意 给你n个折扣,m个物品,每个折扣都可以使用无限次,每次你使用第i个折扣的时候,你必须 ...

随机推荐

  1. python元祖,join(),range()

    一.元祖定义 元组:俗称不可变的列表,又被成为只读列表,元祖也是python的基本数据类型之一,用小括号括起来,里面可以放任何数据类型的数据,查询可以,循环也可以,切片也可以.但就是不能改. 儿子不能 ...

  2. Java多线程设计模式系列

    通过几天的认真阅读,发现这是一本难得一见的好书,为了加深巩固学习成功,我打算将书中的例子全部自己实现一遍,特此记录下来也方便其他朋友学习. 第一章,java语言的线程 单线程程序:打印10000次go ...

  3. Visual Studio 代码管理器svn插件下载

    环境:Visual Studio 2010 Visual Studio的svn插件叫做VisualSVN,可自行到VisualSVN官网上下载相应版本,也可以通过vs中找到相关插件. ps:vs其他的 ...

  4. SF Symbols 使用

    伴随着WWDC 2019 的举办,对于程序员而言 ,无疑SwiftUI 推出 是比较令人兴奋的一件事情, 其中在SwiftUI 使用之中, 我们经常使用以下系统图片 Image(systemName: ...

  5. Java内存问题:java.lang.OutOfMemoryError: PermGen space

    代码运行环境: jdk1.7.0_25 apache-tomcat-8.0.30 详细报错日志: org.springframework.web.util.NestedServletException ...

  6. UMP系统架构 Controller服务器

  7. JS规则 保持先后顺序(操作符优先级)操作符之间的优先级(高到低): 算术操作符 → 比较操作符 → 逻辑操作符 → "="赋值符号

    保持先后顺序(操作符优先级) 我们都知道,除法.乘法等操作符的优先级比加法和减法高,例如: var numa=3; var numb=6 jq= numa + 30 / 2 - numb * 3; / ...

  8. echo 改变字体颜色

    字颜色:30—–37 echo -e “\033[30m 黑色字 \033[0m” echo -e “\033[31m 红色字 \033[0m” echo -e “\033[32m 绿色字 \033[ ...

  9. Java 生成pdf表格文档

    最近在工作做一个泰国的项目,应供应商要求,需要将每天的交易生成pdf格式的报表上传到供应商的服务器,特此记录实现方法.废话不多说,直接上代码: THSarabunNew.ttf该文件是泰国字体自行网上 ...

  10. String相加解析

    Java代码 package com.utils.test; public class TestObject { public static void main(String[] args) { St ...