Codeforces Round #447 (Div. 2) 题解
Problem A
直接暴力,当然我O(n)过的。
#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 ans = 0;
char s[205];
int a[205], b[205];
int n;
int main(){
scanf("%s", s + 1);
n = strlen(s + 1);
rep(i, 1, n) if (s[i] == 'Q') a[i] = a[i - 1] + 1;
else a[i] = a[i - 1];
dec(i, n, 1) if (s[i] == 'Q') b[i] = b[i + 1] + 1;
else b[i] = b[i + 1];
rep(i, 1, n) if (s[i] == 'A') ans += a[i] * b[i];
printf("%d\n", ans);
return 0;
}
Problem B
打表找规律……当k为-1且n和m奇偶性不同的时候答案为0。
#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 LL mod = 1e9 + 7;
LL n, m;
int k;
inline LL Pow(LL a, LL b, LL Mod){
LL ret(1);
for (; b; b >>= 1, (a *= a) %= Mod) if (b & 1) (ret *= a) %= Mod;
return ret;
}
int main(){
scanf("%lld%lld%d", &n, &m, &k);
if (k == 1){
LL yy = n - 1;
LL hh = Pow(2, yy, mod);
LL ans = Pow(hh, m - 1, mod);
printf("%lld\n", ans);
}
else{
LL tt = n + m;
if (tt % 2 == 1) return 0 * puts("0");
if (n % 2 == 1){
LL oo = (n + 1) / 2;
LL pp = oo - 1;
LL mul = Pow(16, pp, mod);
LL mm = m / 2;
LL ans = Pow(mul, mm, mod);
printf("%lld\n", ans);
}
else{
LL xx = n / 2, yy = m / 2;
LL mul = 4 * Pow(16, xx - 1, mod) % mod;
LL ff = 2 * Pow(4, xx - 1, mod) % mod;
LL ans = ff * Pow(mul, yy - 1, mod) % mod;
printf("%lld\n", ans);
}
}
return 0;
}
Problem C
构造题(赛时被X……)
若最大的那个不能整除所有比他小的数,那么无解
否则就按照s1,s1,s2,s1,s3,s1,s4,s1,...sn,s1这么输出。
关键是想到。
#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, f) for (int i(a); i <= (f); ++i)
#define dec(i, a, f) for (int i(a); i >= (f); --i)
#define MP make_pair
#define fi first
#define se second
const int N = 1e6;
int n;
int c[10100];
int f[N];
int main(){
scanf("%d", &n);
rep(i, 1, n) scanf("%d", c + i);
rep(i, 2, n) if (c[i] % c[1]) return 0 * puts("-1");
printf("%d\n", n << 1);
rep(i, 1, n) printf("%d %d\n", c[1], c[i]);
putchar(10);
}
Problem D
暴力存下所有点的所有儿子到他的距离。
因为这是完全二叉树所以内存可以承受。
空间开销$nlogn$,时间复杂度$O(nlog^{2}n)$,如果用归并排序的话那就$O(nlogn)$
然后查询的时候一步步往上爬,把符合条件的答案统计进来。
#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, LL> PII;
const int N = 1e6 + 10;
int n, m;
vector <LL > g[N], s[N];
LL l[N], ans = 0;
inline int fa(int x){ return x >> 1;}
inline int ls(int x){ return x << 1;}
inline int rs(int x){ return x << 1 | 1;}
PII calc(int x, LL len){
if (len < 0) return MP(0, 0);
if (x > n) return MP(0, 0);
int sz = (int)g[x].size();
if (g[x][sz - 1] <= len) return MP(sz, s[x][sz - 1]);
int l = 0, r = sz - 1;
while (l + 1 < r){
int mid = (l + r) >> 1;
if (g[x][mid] <= len) l = mid;
else r = mid - 1;
}
int t;
if (g[x][r] <= len) t = r; else t = l;
return MP(t + 1, s[x][t]);
}
void dfs(int x){
if (ls(x) <= n){
dfs(ls(x));
for (auto u : g[ls(x)]) g[x].push_back(l[ls(x)] + u);
}
if (rs(x) <= n){
dfs(rs(x));
for (auto u : g[rs(x)]) g[x].push_back(l[rs(x)] + u);
}
g[x].push_back(0);
sort(g[x].begin(), g[x].end());
}
int main(){
scanf("%d%d", &n, &m);
rep(i, 2, n) scanf("%lld", l + i);
dfs(1);
rep(i, 1, n){
int sz = g[i].size();
s[i].resize(sz + 2);
s[0] = g[0];
rep(j, 1, sz - 1) s[i][j] = s[i][j - 1] + g[i][j];
}
while (m--){
int x, y;
LL len, Len;
scanf("%d%lld", &x, &len);
Len = len;
PII cnt = calc(x, len);
ans = 0;
ans = cnt.fi * len - cnt.se;
y = x, x = fa(x);
len -= l[y];
while (x && len >= 0){
if (ls(x) == y){
cnt = calc(rs(x), len - l[rs(x)]);
ans += cnt.fi * Len - cnt.se - cnt.fi * (Len - len + l[rs(x)]);
}
else{
cnt = calc(ls(x), len - l[ls(x)]);
ans += cnt.fi * Len - cnt.se - cnt.fi * (Len - len + l[ls(x)]);
}
ans += len;
y = x;
x = fa(x);
len -= l[y];
}
printf("%lld\n", ans);
}
return 0;
}
Problem E
预处理出所有强连通分量之后缩点。
缩成的点的权值为该点代表的强连通分量的所有边的价值和(根据题目算出来)
然后就变成了一个DAG,DP一下就可以了。
#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;
vector <pair <int, int > > v[N], g[N];
stack <int> stk;
LL f[N], val[N];
int n, m;
int low[N], dfn[N], sccno[N];
int num = 0, ti = 0;
int s;
void dfs(int x){
low[x] = dfn[x] = ++ti;
stk.push(x);
for (auto edge : v[x]){
int u = edge.fi, w = edge.se;
if (!low[u]){
dfs(u);
dfn[x] = min(dfn[x], dfn[u]);
}
else if (!sccno[u]) dfn[x] = min(dfn[x], low[u]);
}
if (dfn[x] == low[x]){
++num;
while (true){
int u = stk.top();
stk.pop();
sccno[u] = num;
if (u == x) break;
}
}
}
LL work(int x){
if (~f[x]) return f[x];
f[x] = 0;
for (auto edge : g[x]) f[x] = max(f[x], work(edge.fi) + edge.se);
return f[x] += val[x];
}
LL calc(int x){
int rt = sqrt(2 * x);
while ((LL)rt * (rt - 1) / 2 <= x) rt++;
while ((LL)rt * (rt - 1) / 2 > x) rt--;
return (LL)rt * x - (LL)(rt + 1) * rt * (rt - 1) / 6;
}
int main(){
scanf("%d%d", &n, &m);
rep(i, 1, m){
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
v[x].push_back(MP(y, z));
}
scanf("%d", &s);
dfs(s);
rep(i, 1, n){
for (auto edge : v[i]){
int x = i, y = edge.fi;
if (sccno[x] == sccno[y]) val[sccno[x]] += calc(edge.se);
else g[sccno[x]].push_back(MP(sccno[y], edge.se));
}
}
memset(f, -1, sizeof f);
printf("%lld\n", work(sccno[s]));
return 0;
}

浙公网安备 33010602011771号