题目链接 Codeforces Educational Round 33
Problem A
按照题目模拟,中间发现不对就直接输出NO。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
int a, b, c, n;
int main(){
a = 1, b = 2, c = 3;
scanf("%d", &n);
rep(i, 1, n){
int x;
scanf("%d", &x);
if (x != a && x != b) return 0 * puts("NO");
if (x == a) swap(b, c); else swap(a, c);
}
puts("YES");
return 0;
}
Problem B
打表然后塞到set里面,然后查找一下。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
int c[20];
int a[100010];
int n;
int cnt, et;
set <int> s;
int main(){
rep(i, 1, 10){
int a = (1 << i) - 1;
int b = (1 << (i - 1));
s.insert(a * b);
}
rep(i, 1, et) printf("%d
", c[i]);
scanf("%d", &n);
rep(i, 1, n) if (n % i == 0) a[++cnt] = i;
dec(i, cnt, 1) if (s.count(a[i])) return 0 * printf("%d
", a[i]);;
return 0;
}
Problem C
在每个连通块里面找个权值最小的然后加起来即可。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
const int N = 1e6 + 10;
LL a[N];
LL now;
LL ans = 0;
int vis[N];
vector <int> v[N];
int n, m;
void dfs(int x){
vis[x] = 1;
now = min(now, a[x]);
for (auto u : v[x]){
if (!vis[u]) dfs(u);
}
}
int main(){
scanf("%d%d", &n, &m);
rep(i, 1, n) scanf("%lld", a + i);
rep(i, 1, m){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
rep(i, 1, n) if (!vis[i]){
now = 1e10;
dfs(i);
ans += now;
}
printf("%lld
", ans);
return 0;
}
Problem D
考虑每一天的时候,记录min和max,分别表示钱的下限值和上限值。
如果min都超过d了那肯定不行了,输出-1。
check的时候根据mx是否非负来决定是否更新答案。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
int n, d;
int x;
int mi = 0, mx = 0;
int ans;
int main(){
scanf("%d%d", &n, &d);
rep(i, 1, n){
scanf("%d", &x);
if (x){
mi += x, mx += x;
if (mi > d) return 0 * puts("-1");
mx = min(mx, d);
}
else{
if (mx >= 0) mi = max(mi, 0);
else ++ans, mx = d, mi = 0;
}
}
printf("%d
", ans);
return 0;
}
Problem E
首先来个预处理,把所有的数的质因子以及指数求出来。
然后对于每一个质因子c,找到他的指数d。
转化成盒子里面放小球的问题。
(盒子不同,小球相同,允许空盒子的情况)
那么当前质因子c对答案的贡献即为$C(y + d - 1, d)$
由于各质因子之间是独立的,所以直接相乘即可。
最后还有-1的情况,对整个ans乘上$2^{y - 1}$即可。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
typedef pair <int, int> PII;
const int N = 2e6 + 10;
const int mod = 1e9 + 7;
int fac[N];
int c[N];
int val[N];
int ret, q, x, y;
int inv[N];
vector <PII> pri[N];
inline int Pow(int a, int b, int mod){
int ret = 1;
for (; b; b >>= 1, a = 1ll * a * a % mod) if (b & 1) ret = 1ll * ret * a % mod;
return ret;
}
inline int C(int n, int k){ return 1ll * fac[n] * inv[k] % mod * inv[n - k] % mod; }
void init(){
fac[0] = 1;
rep(i, 1, 2e6 + 3) fac[i] = 1ll * fac[i - 1] * i % mod;
rep(i, 0, 2e6 + 3) inv[i] = Pow(fac[i], mod - 2, mod);
rep(i, 1, 1e6 + 3) val[i] = i;
rep(i, 2, 1e6 + 3) if (!c[i]){
for (int j = i * 2; j <= 1e6 + 3; j += i){
c[j] = 1;
int cnt = 0;
while (val[j] % i == 0) val[j] /= i, ++cnt;
pri[j].push_back(MP(i, cnt));
}
}
rep(i, 2, 1e6 + 3) if (val[i] > 1)
pri[i].push_back(MP(i, 1));
}
int main(){
init();
scanf("%d", &q);
while (q--){
int x, y;
scanf("%d%d", &x, &y);
ret = Pow(2, y - 1, mod);
for (auto u : pri[x]){
int d = u.se;
ret = 1ll * ret * C(y + d - 1, d) % mod;
}
printf("%d
", ret);
}
return 0;
}
Problem F
对于每一个结点,维护以他为根的子树中深度在[l, r]范围内的所有点的权值的最小值。
一开始每个点在空树的基础上在自己这个深度插入自己的权值。
每个点的插入复杂度为$O(logn)$,因为要开$logn$棵线段树。
然后dfs一遍,做$n$次线段树合并即可。
查询的时候对询问的距离$d$加上当前结点的深度$deep$,这样就构成了一个询问区间$[1, d + deep]$。
为什么左端点是$1$呢,因为当前结点代表的线段树在$[1, deep - 1]$内都没有信息,那么$[1, d + deep]$就可以等效题目的询问区间。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i(a); i <= (b); ++i)
#define dec(i, a, b) for (int i(a); i >= (b); --i)
#define MP make_pair
#define fi first
#define se second
typedef long long LL;
const int N = 1e5 + 10;
const int M = 2e7 + 10;
int father[N], deep[N];
int n, r;
vector <int> v[N];
int a[N];
int t[M], ls[M], rs[M];
int tot = 0;
int val[M];
int m;
int ans;
void dfs(int x, int fa, int dep){
deep[x] = dep;
father[x] = fa;
for (auto u : v[x]){
if (u == fa) continue;
dfs(u, x, dep + 1);
}
}
int ins(int x, int a, int b, int c, int p){
int y = ++tot;
val[y] = min(val[x], p);
if (a == b) return y;
int mid = (a + b) >> 1;
if (c <= mid) ls[y] = ins(ls[x], a, mid, c, p), rs[y] = rs[x];
else ls[y] = ls[x], rs[y] = ins(rs[x], mid + 1, b, c, p);
return y;
}
int ask(int x, int a, int b, int d){
if (b <= d) return val[x];
int mid = (a + b) >> 1, t = ask(ls[x], a, mid, d);
if (d > mid) t = min(t, ask(rs[x], mid + 1, b, d));
return t;
}
int merge1(int x, int y, int a, int b){
if (!x || !y) return x + y;
int z = ++tot;
val[z] = min(val[x], val[y]);
if (a == b) return z;
int mid = (a + b) >> 1;
ls[z] = merge1(ls[x], ls[y], a, mid);
rs[z] = merge1(rs[x], rs[y], mid + 1, b);
return z;
}
void work(int x, int fa){
for (auto u : v[x]){ if (u == fa) continue; work(u, x); }
for (auto u : v[x]){
if (u == fa) continue;
t[x] = merge1(t[x], t[u], 1, n);
}
}
int main(){
scanf("%d%d", &n, &r);
rep(i, 1, n) scanf("%d", a + i);
rep(i, 0, 2e7) val[i] = 2147000000;
rep(i, 2, n){
int x, y;
scanf("%d%d", &x, &y);
v[x].push_back(y);
v[y].push_back(x);
}
dfs(r, 0, 1);
rep(i, 1, n) t[i] = ins(0, 1, n, deep[i], a[i]);
work(r, 0);
ans = 0;
scanf("%d", &m);
while (m--){
int x, y;
scanf("%d%d", &x, &y);
x = ((x + ans) % n) + 1;
y = ((y + ans) % n);
y += deep[x];
if (y > n) y = n;
printf("%d
", ans = ask(t[x], 1, n, y));
}
return 0;
}