16.0

邮寄

有史以来考的最好的一次。

开场秒 B。

A 想了一个做法。然后光速假掉,加了个三分勉强能行。

然后 cd 不会。

A

显然可以三分科技使用次数,然后 RMQ 计算答案。

#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node {
int id, t;
bool operator >(const node &b) const {
return t > b.t;
}
};
int n, k, arr[100010], fa[100010][22], fw[100010][22];
vector<int> v;
long long check(int x) {
long long rs = 0;
for(int i = 1; i <= n; i++) {
int c = 0, t = i;
for(int j = 20; j >= 0; j--) {
if(c + fw[t][j] <= x) {
c += fw[t][j];
t = fa[t][j];
}
}
rs += arr[t];
}
return rs + k * x;
}
long long lmrm() {
int l = 0, r = n + 2;
long long ans = LLONG_MAX;
for(; l <= r; ) {
int len = (r - l) / 3;
int lmid = l + len, rmid = r - len;
if(check(lmid) <= check(rmid)) {
ans = min(ans, check(lmid));
r = rmid - 1;
}else {
ans = min(ans, check(rmid));
l = lmid + 1;
}
}
return ans;
}
signed main() {
freopen("collect.in", "r", stdin);
freopen("collect.out", "w", stdout);
cin >> n >> k;
for(int i = 1; i <= n; i++) {
cin >> arr[i];
}
rotate(arr + 1, min_element(arr + 1, arr + n + 1), arr + n + 1);
for(int i = n; i >= 1; i--) {
fw[i][0] = 100000000;
for(; v.size() && arr[v.back()] > arr[i]; v.pop_back()) {
fw[v.back()][0] = v.back() - i;
fa[v.back()][0] = i;
}
v.push_back(i);
}
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= 20; j++) {
fa[i][j] = fa[fa[i][j - 1]][j - 1];
fw[i][j] = fw[i][j - 1] + fw[fa[i][j - 1]][j - 1];
}
}
cout << lmrm() << '\n';
return 0;
}

B

容斥,倍增。

#include <bits/stdc++.h>
#define int long long
using namespace std;
struct node {
int lc, rc;
}ctl[200020], ctg[200020];
int n, arr[200020], fl[200020][22], fr[200020][22], rcl, rcg;
long long ans;
vector<int> v;
// 5.1 Minimum, except in both
void TVl(int x, int l, int r) {
if(!x) {
return ;
}
ans -= (r - l);
int cl = x, cr = x;
for(int i = 20; i >= 0; i--) {
if(fl[cl][i] >= l) {
cl = fl[cl][i];
ans += (1 << i);
}
if(fr[cr][i] <= r) {
cr = fr[cr][i];
ans += (1 << i);
}
}
TVl(ctl[x].lc, l, x - 1);
TVl(ctl[x].rc, x + 1, r);
}
// 5.2 Maximum
void TVg(int x, int l, int r) {
if(!x) {
return ;
}
ans -= (r - l);
TVg(ctg[x].lc, l, x - 1);
TVg(ctg[x].rc, x + 1, r);
}
signed main() {
freopen("interval.in", "r", stdin);
freopen("interval.out", "w", stdout);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> arr[i];
}
// 1. Cartesian, <
for(int i = 1; i <= n; i++) {
if(!v.size()) {
v.push_back(i);
continue;
}
for(; v.size() > 1 && arr[v.back()] > arr[i]; v.pop_back()) {
ctl[i].lc = v.back();
}
if(arr[v.back()] > arr[i]) {
ctl[i].lc = v.back();
v.pop_back();
}else {
ctl[v.back()].rc = i;
}
v.push_back(i);
}
rcl = v[0];
v.clear();
// 2. Cartesian, >
for(int i = 1; i <= n; i++) {
if(!v.size()) {
v.push_back(i);
continue;
}
for(; v.size() > 1 && arr[v.back()] < arr[i]; v.pop_back()) {
ctg[i].lc = v.back();
}
if(arr[v.back()] < arr[i]) {
ctg[i].lc = v.back();
v.pop_back();
}else {
ctg[v.back()].rc = i;
}
v.push_back(i);
}
rcg = v[0];
v.clear();
// 3. Left-first, >
for(int i = n; i >= 1; i--) {
for(; v.size() && arr[v.back()] < arr[i]; v.pop_back()) {
fl[v.back()][0] = i;
}
v.push_back(i);
}
v.clear();
for(int i = 1; i <= n; i++) {
for(int j = 1; j <= 20; j++) {
fl[i][j] = fl[fl[i][j - 1]][j - 1];
}
}
/*
for(int i = 1; i <= n; i++) {
cout << fl[i][0] << ' ';
}
cout << '\n';
//*/
// 4. Right-first, >
for(int i = 0; i <= 20; i++) {
fr[n + 1][i] = n + 1;
}
for(int i = 1; i <= n; i++) {
for(; v.size() && arr[v.back()] < arr[i]; v.pop_back()) {
fr[v.back()][0] = i;
}
v.push_back(i);
}
for(int i = n; i >= 1; i--) {
if(!fr[i][0]) {
fr[i][0] = n + 1;
}
for(int j = 1; j <= 20; j++) {
fr[i][j] = fr[fr[i][j - 1]][j - 1];
}
}
/*
for(int i = 1; i <= n; i++) {
cout << fr[i][0] << ' ';
}
cout << '\n';
//*/
// 5. Cal ans
ans = 1ll * n * (n - 1) / 2;
TVl(rcl, 1, n);
TVg(rcg, 1, n);
cout << ans << '\n';
return 0;
}
//Cartesian (<, >), Left-first with fa[200020][20], Right-first with fa[200020][20]

C

定义转移矩阵 A(c)i,j={1if c is the j-th character or i=j0otherwise

然后就可以 121312141213121 做了。

答案矩阵 B(i)=B(i+1)×A(si)×B(i+1)

#include <bits/stdc++.h>
using namespace std;
const int kMod = int(1e9) + 7;
struct node {
int a[27][27];
node() {
memset(a, 0, sizeof(a));
}
auto operator [](int x) {
return a[x];
}
void init() {
for(int i = 0; i <= 26; i++) {
a[i][i] = 1;
}
}
node operator *(node b) {
node rs;
for(int i = 0; i <= 26; i++) {
for(int j = 0; j <= 26; j++) {
for(int k = 0; k <= 26; k++) {
rs[i][j] = (rs[i][j] + 1ll * a[i][k] * b[k][j]) % kMod;
}
}
}
return rs;
}
};
int n, ans;
char c[550];
node convs(char c) {
node rs;
for(int i = 0; i <= 26; i++) {
if(c - 'a' == i) {
fill(rs[i], rs[i] + 27, 1);
}else {
rs[i][i] = 1;
}
}
return rs;
}
node solve(int x) {
if(x > n) {
node tmp;
tmp.init();
return tmp;
}
node tmp = solve(x + 1);
return tmp * convs(c[x]) * tmp;
}
int main() {
freopen("subseq.in", "r", stdin);
freopen("subseq.out", "w", stdout);
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> c[i];
}
node rs = solve(1);
for(int i = 0; i < 26; i++) {
ans = (ans + rs[i][26]) % kMod;
}
cout << ans << '\n';
return 0;
}

D

首先建出 DFS 树。

显然,删除的两条边中必然有一条是树边。

注意:我们不考虑树边中存在桥的情况。

  1. 树+其他

此时,这个其他一定是唯一一个覆盖了这条树边的其他边。

  1. 树+树

此时,覆盖了这两个树边的的其他边的集合 相同

然后,对于 2.,使用 xor hash 维护。

#include <bits/stdc++.h>
#define st first
#define nd second
#define u64 unsigned long long
#define int long long
using namespace std;
int n, m, k, u, v, is[200020], dfn[200020], low[200020], dcnt, cnt[200020], vis[200020];
long long ans;
random_device rd;
mt19937_64 mt(rd());
u64 sum[200020];
map<u64, int> mp;
multiset<pair<int, int> > to[200020];
void DFS(int x, int pd) {
dfn[x] = low[x] = ++dcnt;
for(auto i : to[x]) {
if(!dfn[i.st]) {
DFS(i.st, i.nd);
low[x] = min(low[x], low[i.st]);
if(low[i.st] > dfn[x]) {
is[i.st] = 1;
}
}else {
if(i.nd != pd) {
if(dfn[i.st] < dfn[x]) {
int tmp = mt();
cnt[x]++, sum[x] ^= tmp;
cnt[i.st]--, sum[i.st] ^= tmp;
}
low[x] = min(low[x], dfn[i.st]);
}
}
}
}
void cal(int x) {
vis[x] = 1;
for(auto i : to[x]) {
if(!vis[i.st]) {
cal(i.st);
cnt[x] += cnt[i.st];
sum[x] ^= sum[i.st];
}
}
}
signed main() {
//#ifndef LOCAL
freopen("attack.in", "r", stdin);
freopen("attack.out", "w", stdout);
//#endif
cin >> n >> m >> k;
for(int i = 1; i <= m; i++) {
cin >> u >> v;
to[u].insert({v, i});
to[v].insert({u, i});
}
if(k == 1) {
DFS(1, 0);
cout << accumulate(is + 1, is + n + 1, 0) << '\n';
}else {
DFS(1, 0);
cal(1);
int cur = m;
for(int i = 2; i <= n; i++) {
if(is[i]) {
ans += cur;
cur--;
}else {
ans += (cnt[i] == 1);
mp[sum[i]]++;
}
}
for(auto i : mp) {
ans += i.second * (i.second - 1) / 2;
}
cout << ans << '\n';
}
return 0;
}
posted @   hhc0001  阅读(9)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
点击右上角即可分享
微信分享提示