A
数组sum表示前i个字符中元音的数量,即前缀和
我们处理出每个长度的期望,再称上概率
令数组f[i]表示长度为i的子串中元音的总数,,,
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
char str[maxn];
int main()
{
scanf("%s", str + 1);
int n = strlen(str + 1);
vector<ll> sum(n + 1), f(n + 1);
for (int i = 1; i <= n; ++i) {
sum[i] = sum[i - 1];
if (str[i] == 'a' || str[i] == 'e' || str[i] == 'i' || str[i] == 'o' || str[i] == 'u' || str[i] == 'y')
sum[i]++;
}
for (int i = 1; i <= n; ++i)
f[i] = f[i - 1] + sum[n - i + 1] - sum[i - 1];
long double ans = 0;
for (int i = 1; i <= n; ++i)
ans += (1.0 * f[i] / i);
ans *= 2;
ans /= 1ll * n * (n + 1);
printf("%.10Lf\n", ans);
}
C
nim游戏变形,令x表示为前i个数的异或和,答案即是满足y<x^y的y数量
分析y<x^y,发现只有当x的二进制出现第一个1时(由大到小)会决定该数是否满足答案;若y的该位也为1,则x^y会小于y;该位为0时,x^y的该位为1大于y
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
const int digit = 60 + 2;
vector<ll> v;
int tr[maxn << 1][digit];
int lowbit(int x) {
return x & -x;
}
void add(int i, int n, ll val) {
while (i <= n) {
for (int j = 0; j < digit; ++j)
if ((val >> j) & 1)
tr[i][j]++;
i += lowbit(i);
}
}
int sum(int i, int k) {
int rhs = 0;
while (i) {
rhs += tr[i][k];
i -= lowbit(i);
}
return rhs;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n; cin >> n;
v.resize(n + 1);
for (int i = 1; i <= n; ++i) {
cin >> v[i];
add(i, n, v[i]);
}
ll xor_val = 0;
for (int i = 1; i <= n; ++i) {
xor_val ^= v[i];
int k = -1;
for (int j = digit; j >= 0; --j) {
if ((xor_val >> j) & 1) {
k = j;
break;
}
}
if (k == -1)
cout << 0 << '\n';
else
cout << sum(i, k) << '\n';
}
}
E
计算子树中结点标号的平方和,树上启发式合并
将信息保存到重儿子中,复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
vector<int> e[maxn];
int fa[maxn], sz[maxn], son[maxn];
ll ans[maxn];
//重链剖分
void dfs(int u) {
sz[u] = 1;
for (int v : e[u]) {
fa[v] = u;
dfs(v);
sz[u] += sz[v];
if (!son[u] || sz[son[u]] < sz[v])
son[u] = v;
}
}
set<ll> s;
ll res;
int Son;
//计算答案
void calc(int u) {
s.insert(u);
auto it = s.find(u);
if (s.size() == 1) {
}
else if (it == s.begin()) {
ll x = *(++s.begin()) - u;
res += x * x;
}
else if (it == (--s.end())) {
ll x = (*(--it)) - u;
res += x * x;
}
else {
auto itt = it;
ll a = *(--it), b = u, c = *(++itt);
res -= (a - c) * (a - c);
res += (a - b) * (a - b) + (b - c) * (b - c);
}
for (int v : e[u]) {
if (v == Son)
continue;
calc(v);
}
}
//计算子树信息
void solve(int u, int keep) {
for (int v : e[u]) {
if (v == son[u])
continue;
solve(v, false);
}
if (son[u]) {
solve(son[u], true);
Son = son[u];
}
calc(u);
Son = 0;
ans[u] = res;
if (!keep) {
s.clear();
res = 0;
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0);
int n; cin >> n;
for (int i = 2; i <= n; ++i) {
int x; cin >> x;
e[x].push_back(i);
}
dfs(1);
solve(1, true);
for (int i = 1; i <= n; ++i)
cout << ans[i] << '\n';
}
K
ac自动机的trie树上跑最短路
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 5;
const ll inf = 1e18;
struct Aho
{
int ch[maxn][26], fail[maxn], val[maxn], cnt[maxn], len[maxn], tot = 0;
void insert(char* s, int value) {
int u = 0;
for (int i = 0; s[i]; ++i) {
int id = s[i] - 'a';
if (!ch[u][id])
ch[u][id] = ++tot;
u = ch[u][id];
len[u] = i + 1;
}
val[u] = val[u] == 0 ? value : min(val[u], value);
cnt[u]++;
}
void build() {
queue<int> q;
for (int i = 0; i < 26; ++i) {
if (ch[0][i]) {
fail[ch[0][i]] = 0;
q.push(ch[0][i]);
}
}
while (!q.empty()) {
int u = q.front(); q.pop();
for (int i = 0; i < 26; ++i) {
if (ch[u][i]) {
fail[ch[u][i]] = ch[fail[u]][i];
q.push(ch[u][i]);
}
else
ch[u][i] = ch[fail[u]][i];
}
}
}
int query(char* s) {
int now = 0, ans = 0;
for (int i = 0; s[i]; ++i) {
now = ch[now][s[i] - 'a'];
for (int j = now; j && cnt[j] != -1; j = fail[j]) {
ans += cnt[j];
cnt[j] = -1;
}
}
return ans;
}
} aho;
char s[maxn];
ll dp[maxn];
int main()
{
int n, m; scanf("%d", &n);
for (int i = 0; i < n; ++i) {
int x; scanf("%s%d", s, &x);
aho.insert(s, x);
}
aho.build();
scanf("%s", s + 1); m = strlen(s + 1);
for (int i = 1; i <= m; ++i)
dp[i] = inf;
for (int i = 1, now = 0; i <= m; ++i) {
now = aho.ch[now][s[i] - 'a'];
int u = now;
while (u) {
if (aho.cnt[u])
dp[i] = min(dp[i], dp[i - aho.len[u]] + aho.val[u]);
u = aho.fail[u];
}
}
if (dp[m] >= inf)
printf("-1\n");
else
printf("%lld\n", dp[m]);
}
H
要求出现1-2,1-3,…,1-n,2-3,2-4,…,2-n,…,n-1-n的
即欧拉路径(要求走满所有路径);因为需要满足度数为奇数的点只能是0或2,不满足条件为偶数的情况,所以我们需要保留两个点,将其他点互相连接
求最大情况,我们二分m,需要的n,基础是完全图m*(m-1)/2条边,若为偶数m,加上m-2互相连接的(m-2)/2条边,最后再加上1转换为点数
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e6 + 5;
const int maxm = maxn << 1;
ll cal(ll m) {
if (m == 2)
return 2;
ll rhs = m * (m - 1) / 2;
if (m % 2 == 0)
rhs += m / 2;
else
rhs++;
return rhs;
}
ll solve(ll n) {
ll st = 1, ed = 2e9;
while (st != ed) {
ll md = (st + ed + 1) >> 1;
if (cal(md) <= n)
st = md;
else
ed = md - 1;
}
return st;
}
vector<int> pr;
int head[maxn], tot = 0;
struct enode {
int to, nxt;
} e[maxm];
void addedge(int u, int v) {
e[tot] = {v, head[u]};
head[u] = tot++;
}
bool used[maxm];
stack<int> stk;
void euler(int u) {
stk.push(u);
while (stk.size()) {
int u = stk.top();
int i = head[u];
while (i != -1 && used[i])
i = e[i].nxt;
if (i != -1) {
stk.push(e[i].to);
used[i] = used[i ^ 1] = true;
head[u] = e[i].nxt;
}
else {
stk.pop();
pr.push_back(u);
}
}
}
int main()
{
ll n; scanf("%lld", &n);
ll m; printf("%lld\n", m = solve(n));
if (n > 2e6)
return 0;
memset(head, -1, sizeof(head));
for (int i = 1; i <= m; ++i) {
for (int j = i + 1; j <= m; ++j) {
addedge(i, j);
addedge(j, i);
}
}
if (m % 2 == 0) {
for (int i = 3; i <= m; i += 2) {
addedge(i, i + 1);
addedge(i + 1, i);
}
}
euler(1);
while (pr.size() < n)
pr.push_back(1);
for (int i = 0; i < pr.size(); ++i) {
if (i == 0)
printf("%d", pr[i]);
else
printf(" %d", pr[i]);
}
printf("\n");
}
F
我们考虑每次询问遍历s连接的所有边,乘上连接的子树中的点数
树链剖分+线段树维护
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
vector<pair<int, int>>e[maxn];
int fa[maxn], sz[maxn], son[maxn], dep[maxn];
int top[maxn], id[maxn], rk[maxn];
int tot;
void dfs1(int u, int father) {
dep[u] = dep[father] + 1; fa[u] = father; sz[u] = 1;
for (auto &i : e[u]) {
int v = i.first;
if (v == father) continue;
dfs1(v, u);
sz[u] += sz[v];
if (sz[son[u]] < sz[v])
son[u] = v;
}
}
void dfs2(int u, int root) {
top[u] = root; id[u] = ++tot; rk[tot] = u;
if (son[u])
dfs2(son[u], u);
for (auto i : e[u]) {
int v = i.first;
if (v == fa[u] || v == son[u])
continue;
dfs2(v, u);
}
}
ll t[maxn << 2];
void pushup(int rt) {
t[rt] = t[rt << 1] + t[rt << 1 | 1];
}
void update(int rt, int l, int r, int pos, int val) {
if (l == r) {
t[rt] += val;
return;
}
int mid = (l + r) >> 1;
if (pos <= mid)
update(rt << 1, l, mid, pos, val);
else
update(rt << 1 | 1, mid + 1, r, pos, val);
pushup(rt);
}
ll query(int rt, int l, int r, int L, int R) {
if (L <= l && r <= R)
return t[rt];
int mid = (l + r) >> 1;
ll rhs = 0;
if (L <= mid)
rhs += query(rt << 1, l, mid, L, R);
if (mid < R)
rhs += query(rt << 1 | 1, mid + 1, r, L, R);
return rhs;
}
int main()
{
int n; scanf("%d", &n);
int s = 1;
for (int i = 1; i < n; ++i) {
int u, v, w; scanf("%d%d%d", &u, &v, &w);
e[u].push_back(make_pair(v, w));
e[v].push_back(make_pair(u, w));
}
dfs1(1, 0);
dfs2(1, 0);
int m; scanf("%d", &m);
while (m--) {
int op, v, x; scanf("%d%d", &op, &v);
if (op == 1) {
scanf("%d", &x);
update(1, 1, n, id[v], x);
}
else s = v;
ll rhs = 0;
for (auto i : e[s]) {
int v = i.first, w = i.second;
if (v == fa[s])
rhs += 1ll * w * (t[1] - query(1, 1, n, id[s], id[s] + sz[s] - 1));
else
rhs += 1ll * w * query(1, 1, n, id[v], id[v] + sz[v] - 1);
}
printf("%lld\n", rhs);
}
}
来源:CSDN
作者:swpu_cd
链接:https://blog.csdn.net/weixin_40588429/article/details/104116996