Educational Codeforces Round 118 (Rated for Div. 2)
A Long Comparison
题目:
给定两个整数a,b然后在后面补上若干个0,比较大小
解决:
减去共同长度的0,然后拼接到a,b后面
用字符串可以直接比较大小
代码:
string a, b;
int x, y;
void work()
{
cin >> a >> x;
cin >> b >> y;
int d = min(x, y);
x -= d;
y -= d;
// cout << a.size() + x << " " << b.size() + y << endl;
if (a.size() + x > b.size() + y)
{
puts(">");
}
else if (a.size() + x < b.size() + y)
{
puts("<");
}
else
{
for (int i = 0; i < x; i ++ ) a += "0";
for (int j = 0; j < y; j ++ ) b += "0";
// cout << a << " " << b << endl;
if (a > b) puts(">");
else if (a < b) puts("<");
else puts("=");
}
}
B Absent Remainder
题目:
给定一个长度为n的序列,让你找到 n / 2(向下取整)对元素(x,y),使得:
- x != y
- x y属于序列
- x % y 不属于序列
1≤ai≤1e6
2≤n≤2⋅1e5
解决:
看数据范围可以知道a[i] >= 1
我们先给序列sort一下。
如果a[1] == 1,那么任意一个数对1取模一定为0,0不存在与序列,合法
如果a[1] > 1, 那么任意一个数a[i] % a[1],得到的数一定是范围[0,a[1]-1]之内的,因为a[1]是最小的数,所以也是合法的
结论,直接输出n/2(下取整)对(a[1], a[i >=2])即可
代码:
int n;
int a[N], c[N];
void work()
{
scanf("%d", &n);
memset(c, 0, sizeof c);
for (int i = 1; i <= n; i ++ )
{
scanf("%d", &a[i]);
c[a[i]] ++;
}
sort(a + 1, a + 1 + n);
int cnt = 0;
for (int i = 2; i <= n; i ++ )
if (c[a[i] % a[1]] == 0)
{
printf("%d %d\n", a[i], a[1]);
cnt ++;
if (cnt == n / 2) break;
}
}
C Poisoned Dagger
题目:
在一个数轴上,有n个防火点,当遍历到当前点时火焰可以从当前点开始向右燃烧,燃烧时间是k秒,每秒燃烧一米,当前点算第一秒
现在时常k我们可以自己控制,问k最小为多少,可以保证燃烧的总长度是h
1≤n≤100;1≤h≤1018
解决:
二分,二分时长k,判断够不够h米
代码:
int n;
LL h;
LL a[N];
bool check(LL mid)
{
LL ans = 0;
if (mid > h) return true;
for (int i = 1; i <= n; i ++ )
{
LL r = min(a[i] + mid - 1, a[i + 1] - 1);
// if (ans + r - a[i] + 1 > h) return true;
ans += r - a[i] + 1;
// printf("%lld\n", ans);
if (ans > h) return true;
}
// printf("mid = %lld, ans = %lld, h = %lld\n", mid, ans, h);
return ans >= h;
}
void work()
{
// puts("------------------");
cin >> n >> h;
for (int i = 1; i <= n; i ++ ) scanf("%lld", &a[i]);
LL l = 0, r = 1ll * 1e18;
a[n + 1] = a[n] + h + 1;
while (l < r)
{
LL mid = l + r >> 1;
if (check(mid)) r = mid;
else l = mid + 1;
}
printf("%lld\n", r);
}
D MEX Sequences
D真的是很精彩的一道题,比赛的时候想到dp了,但是一直没写出来,看了不少代码后才将问题考虑全
题目:
对于任意的ai ,有 |ai - MEX(a1,a2,…,ai)| ≤1
求满足上述式子的方案数
(1≤n≤5⋅105).0≤ai≤n
解决:
我们考虑合法的方案
分为两大种,第一种序列是连续的,第二序列有间段
表示:
dp[i][0/1]
(0表示连续,1表示不连续)对于第一种:
0自成连续
dp[o][0] ++
样例表示:0
已经有了0~x-1,没有x,可以直接在后面添加x,
dp[x][0] = (dp[x - 1][0] + dp[x][0]) % mod
样例表示:0,1,2,2,2,3,3,…,x-1,x-1 + x
已经有了0~x,也可以直接在后面添加x,
dp[x][0] = (dp[x][0] + dp[x][0]) % mod
样例表示:0,1,2,2,2,3,3,…,x-1,x-1,x,x,x+x
对于第二种:
1单独自成间段
dp[1][1] ++
样例表示:1
已经有了0~x-2,没有x,可以直接在后面添加x,x>=2,
dp[x][1] = (dp[x - 2][0] + dp[x][1]) % mod
样例表示:0,1,2,2,2,3,3,…,x-2,x-2 + x
已经有了0~x,也可以直接在后面添加x,
dp[x][1] = (dp[x][1] + dp[x][1]) % mod
样例表示:0,1,2,2,2,3,3,…,x-2,x-2 , x + x
已经有了0~x,如果后面存在x+2,不管中间出没出现过x+1,都可以将中间的空下,直接放在当前x的后面,
dp[x + 2][1] = (dp[x + 2][1] + dp[x + 2][1]) % mod
。为什么不是dp[x + 2][1]+=dp[x][1]
呢?表示的含义不一样,dp[x][1]
可是表示的0,1,2,…,x-2,x-2, …, x , x这种序列,再隔上x+1添加x+2指定不对。样例表示:0,1,2,2,2,3,3,…,x-1,x, x, x + 2, x , x + 2, x - 1, x + 2
0,1,2,4,2,4,3,4
代码:
代码中有注释,并且提供了样例
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 500010;
const LL mod = 998244353;
int n;
int a[N], last[N];
LL dp[N][2];
void work()
{
cin >> n;
for (int i = 0; i <= n + 5; i ++ )
{
dp[i][0] = dp[i][1] = 0;
last[i] = -1;
}
for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
/*
单个的0算,单个的1算,剩下单个的不算
从0开始连续的到a[i]算
从0开始,0,1,...,a[i] - 2, a[i]
*/
// dp[0][0] = 1;
for (int i = 1; i <= n; i ++ )
{
// 构成的序列中0~a[i]都已经出现过了,现在的a[i]可加可不加所以*2倍
dp[a[i]][0] = (dp[a[i]][0] + dp[a[i]][0]) % mod;
// 构成的序列中0~a[i] - 2,a[i]都已经存在了,但是a[i] - 1不存在,这个a[i]可加可不加
dp[a[i]][1] = (dp[a[i]][1] + dp[a[i]][1]) % mod;
// 构成的序列中0~a[i]都已经存在了,但是a[i] + 1不存在,如果后面出现a[i] + 2,可以加在这个序列后面
// 比如合法序列0,1,2,4,2,4,3,4可以供大家食用,拿其中一点,对于第二个2来说,最后一个4可以考虑放在2这个序列后面
// 也可以不放在2后面这个序列,所以dp[4][1] = dp[4][1] + dp[4][1]
// 但是,dp[4][1] != dp[2][1] + dp[4][1]因为中间出现了3也就是a[i]-1
dp[a[i] + 2][1] = (dp[a[i] + 2][1] + dp[a[i] + 2][1]) % mod;
// 序列已经有了0~a[i] - 1,a[i]可以直接放在a[i]-1的后面
if (a[i] - 1 >= 0) dp[a[i]][0] = (dp[a[i] - 1][0] + dp[a[i]][0]) % mod;
else dp[a[i]][0] ++;
// 序列已经有了0~a[i]-2,但是没有a[i]-1,可以直接将a[i]放在a[i]-2的后面
if (a[i] - 2 >= 0) dp[a[i]][1] = (dp[a[i] - 2][0] + dp[a[i]][1]) % mod;
else if (a[i] == 1) dp[a[i]][1] ++;
}
//这里大家可以输出下样例的结果
// for (int i = 0; i <= n + 2; i ++ )
// cout << dp[i][0] << " ";
// cout << endl;
// for (int i = 0; i <= n + 2; i ++ )
// cout << dp[i][1] << " ";
// cout << endl;
LL ans = 0;
for (int i = 0; i <= n + 2; i ++ ) ans = (ans + dp[i][0] + dp[i][1]) % mod;
cout << ans << endl;
}
// 提供两组样例
/*
1
9
0 1 0 1 1 3 0 3 1
答案是133
1
14
1 3 3 0 2 0 1 3 3 3 1 1 3 3
答案是440
*/
int main()
{
int T; cin >> T;
while (T -- ) work();
return 0;
}
下面是是我查阅的代码:
https://codeforces.ml/contest/1613/submission/137715867
https://codeforces.ml/contest/1613/submission/137731034
https://codeforces.ml/contest/1613/submission/137732155
https://codeforces.ml/contest/1613/submission/137733116