Codeforces Edu80
Codeforces Edu80
A
思路
显然,当 \(x\) 在 \(sqrt(d)\) 附近时,\(x + \lceil\frac{d}{x+1}\rceil\) 较小,枚举一下即可。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
typedef long long ll;
ll _, n, d;
int main() {
for (scanf("%lld", &_); _; _--) {
scanf("%lld%lld", &n, &d);
if(d <= n) {
puts("YES");
continue;
}
ll sqt = sqrt(d)-1;
bool fg = false;
for (ll i = sqt; i <= 2*sqt; ++i) {
if(i + (d+i)/(i+1) <= n) {
fg = 1;
break;
}
}
puts(fg? "YES": "NO");
}
return 0;
}
B
思路
显然,当且仅当 \(b = 9,99,999,9999 \dots\) 时满足条件。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
typedef long long ll;
ll _, A, B;
int main() {
for (scanf("%lld", &_); _; _--) {
scanf("%lld%lld", &A, &B);
if(B%10==9) ++B;
int res = 0;
while(B) {
++res;
B /= 10;
}
printf("%lld\n", A*(res-1));
}
return 0;
}
C
思路:
两个数组可拼成一个:
\(a_1, a_2, \dots, a_m, b_m, b_{m-1}, \dots, b_1\)
该问题可用隔板法解释: \(2m\) 个位置与 \(n\) 个数可用 \(n-1\) 个隔板分隔。
最终答案:\(\binom{n+2m-1}{n-1}\)
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+10;
const int mod = 1e9 + 7;
ll fac[maxn], inv[maxn];
ll _, A, B;
ll ksm(ll a, ll n) {
ll res = 1;
while(n) {
if(n & 1) res = res * a % mod;
a = a * a % mod;
n >>= 1;
}
return res;
}
void init() {
fac[0] = 1;
for (int i = 1; i < maxn; ++i) fac[i] = fac[i-1] * i % mod;
inv[maxn-1] = ksm(fac[maxn-1], mod-2);
for (int i = maxn - 2; i >= 0; --i) inv[i] = inv[i+1]*(i+1)%mod;
}
ll C(int n, int m) {
return fac[n] * inv[m] % mod * inv[n-m] % mod;
}
int main() {
init();
int n, m;
scanf("%d%d", &n, &m);
printf("%lld\n", C(n + 2 * m - 1, n-1));
return 0;
}
D
思路
二分最值。
假设临界值为 \(x\),大于等于 \(x\) 的设为 1, 小于 \(x\) 的设为 0。
则对于每个数组,可转为长度为m的01串,我们需要保证 \(bit[i] | bit[j] == 2^{m}- 1\) 即可
将每一个 \(bit[i]\) 插入字典树中。
对于数组 \(i\) ,查询是否有能满足条件的 \(j\) 即可。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 3e5+10;
const int inf = 0x3f3f3f3f;
int n, m, a[maxn][10];
int bit[maxn][10];
int trie[maxn*10][2];
int ed[maxn*10];
int pn = 0;
void insertTree(int x) {
int p = 0;
for (int c, i = 1; i <= m; ++i) {
c = bit[x][i];
if(!trie[p][c]) trie[p][c] = ++pn;
p = trie[p][c];
}
ed[p] = x;
}
int inTree(int x) {
int p = 0;
for (int c, i = 1; i <= m; ++i) {
c = 1 - bit[x][i];
if(!trie[p][c]) {
if(!c && trie[p][!c]) c = 1-c;
else return false;
}
p = trie[p][c];
}
return ed[p];
}
int check(int x) {
memset(trie, 0, sizeof(trie));
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j)
bit[i][j] = (a[i][j] >= x);
insertTree(i);
}
for (int i = 1; i <= n; ++i) {
if(inTree(i))
return i;
}
return 0;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j)
scanf("%d", &a[i][j]);
}
int l = 0, r = inf;
while(l <= r) {
int mid = l + r >> 1;
if(check(mid)) l = mid + 1;
else r = mid - 1;
}
int ans = check(r);
printf("%d %d\n", ans, inTree(ans));
return 0;
}
E
思路
对于一个数,若未曾主动改变过,则最小值为初始位置,否则为 1。
对于其最大值,影响其位置的只有其左边有多少个数。因此,我们只需要用树状数组模拟其改变过程即可,只需在其主动移动或m次操作之后时,更新其最大值位置即可。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn =6e5+10;
int tree[maxn], n, m;
inline int lowbit(int x) { return x&-x; }
inline void modify(int x, int val) { for (int i = x; i < maxn; i += lowbit(i)) tree[i] += val; }
inline int query(int x) {
int res = 0;
for (int i = x; i; i -= lowbit(i)) res += tree[i];
return res;
}
int l[maxn], r[maxn], pos[maxn];
int a[maxn];
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; ++i) scanf("%d", a+i);
for (int i = 1; i <= n; ++i) {
l[i] = r[i] = i;
pos[i] = m + i;
modify(pos[i], 1);
}
for (int x, i = 1; i <= m; ++i) {
x = a[i];
l[x] = 1;
r[x] = max(r[x], query(pos[x]));
modify(pos[x], -1);
pos[x] = m - i + 1;
modify(pos[x], 1);
}
for (int i = 1; i <= n; ++i) r[i] = max(r[i], query(pos[i]));
for (int i = 1; i <= n; ++i) printf("%d %d\n", l[i], r[i]);
return 0;
}
F
留坑,待补。