题目链接

https://codeforces.com/gym/102133

参考题解

A - Tree Orientation

简要题意:

给定 nnn 个结点的无向树,根为 111 号点,问有多少种将边定向的方案,使得出度为 000 的点恰有 mmm 个。

解题思路:

考虑 dpdpdp,每个结点考虑其到父结点的边的定向情况,fp[u][i]fp[u][i]fp[u][i] 表示 uuu 子树内, uuu 结点的边指向父结点时,恰有 iii 个出度为 000 的点的方案数;同理 fd[u][i][0/1]fd[u][i][0/1]fd[u][i][0/1] 表示将边指向 uuu 结点,这里需要额外加一维表示 uuu 是否出度为 000。转移时逐子树合并转移,复杂度分析同树上背包。状态转移见代码。

参考代码:
#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define sz(a) ((int)a.size())
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e3 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;vector<int> G[maxn];
int siz[maxn];
ll fd[maxn][maxn][2], fp[maxn][maxn];
int n, m;void dfs(int u, int f){siz[u] = 1, fd[u][1][1] = fp[u][0] = 1;for(auto &v : G[u]){if(v == f) continue;dfs(v, u);memset(fd[0], 0, sizeof fd[0]);memset(fp[0], 0, sizeof fp[0]);for(int i = siz[u]; i >= 0; --i){for(int j = siz[v]; j >= 0; --j){(fd[0][i + j][0] += fd[u][i][0] * (fd[v][j][0] + fd[v][j][1] + fp[v][j])) %= mod;if(i + j > 0) (fd[0][i + j - 1][0] += fd[u][i][1] * (fd[v][j][0] + fd[v][j][1])) %= mod;(fd[0][i + j][1] += fd[u][i][1] * fp[v][j]) %= mod;(fp[0][i + j] += fp[u][i] * (fd[v][j][0] + fd[v][j][1] + fp[v][j])) %= mod;}}memcpy(fd[u], fd[0], sizeof fd[0]);memcpy(fp[u], fp[0], sizeof fp[0]);siz[u] += siz[v];}
}int main(){ios::sync_with_stdio(0); cin.tie(0);cin >> n >> m;for(int i = 1; i < n; ++i){int u, v; cin >> u >> v;G[u].pb(v), G[v].pb(u);}dfs(1, 0);ll ret = (fd[1][m][0] + fd[1][m][1]) % mod;cout << ret << endl;return 0;
}

B - A Masterpiece

简要题意:

给一个数 nnn,求构造 n×nn×nn×n 的矩阵,满足数 111 到 n2n^2n2 分别出现一次,并且任意相邻的数差值大于 111,且任意一组 nnn 个行下标不同、且列下标不同的数之和相同。

解题思路:

n=1n = 1n=1 时单走一个 111;2≤n≤32 \leq n \leq 32≤n≤3 无解;否则,令 ai,j=(i−1)∗n+ja_{i, j} = (i - 1) * n + jai,j​=(i−1)∗n+j,则仅不满足行内相邻数差值大于 111 这个条件。由和值相同的条件得到任意 ai1,j1−ai1,j2=ai2,j1−ai2,j2a_{i1,j1} - a_{i1, j2} = a_{i2, j1} - a_{i2, j2}ai1,j1​−ai1,j2​=ai2,j1​−ai2,j2​,故仅需要对列进行交换调整答案,一个可行方案为先排列偶数列、再排奇数列。

参考代码:
#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define sz(a) ((int)a.size())
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e2 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;int n;int main(){ios::sync_with_stdio(0); cin.tie(0);cin >> n;if(n == 1){cout << "1" << endl;cout << "1" << endl;}else if(n <= 3){cout << "-1" << endl;}else{cout << n << endl;for(int i = 1; i <= n; ++i){int x = (i - 1) * n;for(int j = 2; j <= n; j += 2) cout << x + j << " ";for(int j = 1; j <= n; j += 2) cout << x + j << " ";cout << endl;}}return 0;
}

C - Auction

简要题意:

给定一个数 nnn,现有 x=1x = 1x=1,ABABAB 两人轮流对 xxx 乘上 222 到 999 中的一个数,AAA 先手,当 x>nx > nx>n 时停止游戏,无法操作的一方输。问是否先手必胜。

解题思路:

逆向考虑,当 x>nx \gt nx>n 为必败态,x∈(⌊n9⌋,n]x \in (\lfloor\frac{n}{9}\rfloor, n]x∈(⌊9n​⌋,n] 为必胜态(存在一种 ×9×9×9 的操作使得对方必败),x∈(⌊⌊n9⌋2⌋,⌊n9⌋]x \in (\lfloor\cfrac{\lfloor\frac{n}{9}\rfloor}{2}\rfloor, \lfloor\frac{n}{9}\rfloor]x∈(⌊2⌊9n​⌋​⌋,⌊9n​⌋] 为必败态(无论乘上多少对方都落入前面那个必胜态),以此类推。

参考代码:
#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define sz(a) ((int)a.size())
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e2 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;int main(){ios::sync_with_stdio(0); cin.tie(0);int T; cin >> T;while(T--){ll n; cin >> n;ll l = n / 9, r = n, d = 9, ret = 1;while(l >= 1){d = d == 2 ? 9 : 2;r = l, l /= d, ret ^= 1;// cout << l << " " << r << " " << ret << endl;}cout << (ret ? "YES" : "NO") << endl;}return 0;
}

F - Financial Reports

简要题意:

给一个数组 aaa,求在进行一次交换操作后的最大子段和,并输出交换方案,交换下标须不同、最大子段和区间非空。

解题思路:

交换后最大子段和必然不减,若最大子段和不变,如果区间长为 111,则任意交换都可以成为答案;若区间长度大于 111,交换最大子段和内部两个下标。否则,考虑答案有增加的交换操作,考虑枚举交换的 O(n2)O(n^2)O(n2) 种情况,对答案有增量意味着交换的其中一个下标 xxx 落在某最大子段和 [l,r][l, r][l,r] 内部、或恰处于边界 l−1,r+1l-1, r+1l−1,r+1 处。故可以枚举下标 xxx,讨论另一个交换下标 yyy:若 y>xy \gt xy>x,则 xxx 左侧 [1,x−1][1, x - 1][1,x−1] 取最大的后缀和,xxx 右侧 [x+1,n][x + 1, n][x+1,n] 取最大的 ay+∑i=x+1paia_y + \sum\limits_{i=x + 1}^{p} a_iay​+i=x+1∑p​ai​,其中 p<yp \lt yp<y。x<yx \lt yx<y 的情况同理。用线段树区间合并可以维护。

参考代码:
#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define sz(a) ((int)a.size())
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
typedef long long ll;
typedef pair<ll, int> pii;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;int a[maxn], n;template<class T>
T max(const T &a, const T &b, const T &c){return max(a, max(b, c));
}
struct Node{ll sum, pmx, lmx, rmx, lpmx, prmx;int p, l, r, lp, rp;friend Node operator + (const Node &a, const Node &b){Node c;c.sum = a.sum + b.sum;tie(c.pmx, c.p) = max(pii(a.pmx, a.p), pii(b.pmx, b.p));tie(c.lmx, c.l) = max(pii(a.lmx, a.l), pii(a.sum + b.lmx, b.l));tie(c.rmx, c.r) = max(pii(b.rmx, b.r), pii(b.sum + a.rmx, a.r));tie(c.lpmx, c.lp) = max(pii(a.lpmx, a.lp), pii(a.lmx + b.pmx, b.p), pii(a.sum + b.lpmx, b.lp));tie(c.prmx, c.rp) = max(pii(b.prmx, b.rp), pii(b.rmx + a.pmx, a.p), pii(b.sum + a.prmx, a.rp));return c;}
} tr[maxn << 2];struct Ans{ll v; int x, y;bool operator < (const Ans &o) const{return v < o.v;}
} ans;void pushUp(int rt){tr[rt] = tr[lson] + tr[rson];
}void build(int l, int r, int rt){if(l == r){tr[rt].sum = tr[rt].pmx = tr[rt].lpmx = tr[rt].prmx = a[l];tie(tr[rt].lmx, tr[rt].l) = max(pii(a[l], l), pii(0, l - 1));tie(tr[rt].rmx, tr[rt].r) = max(pii(a[r], r), pii(0, r + 1));tr[rt].p = tr[rt].lp = tr[rt].rp = l;return;}int mid = gmid;build(l, mid, lson);build(mid + 1, r, rson);pushUp(rt);
}Node query(int l, int r, int rt, int L, int R){// cout << rt << " " << l << " ?? " << r << " " << tr[rt].prmx << " " << tr[rt].rp << endl;if(l >= L && r <= R) return tr[rt];int mid = gmid;if(L <= mid && R > mid) return query(l, mid, lson, L, R) + query(mid + 1, r, rson, L, R);else if(L <= mid) return query(l, mid, lson, L, R);else return query(mid + 1, r, rson, L, R);
}int main(){ios::sync_with_stdio(0); cin.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> a[i];build(1, n, 1);Ans ans = Ans{a[1], 1, 1};for(int i = 1; i <= n; ++i){Node ln = i > 1 ? query(1, n, 1, 1, i - 1) : Node();Node rn = i < n ? query(1, n, 1, i + 1, n) : Node();if(i > 1) ans = max(ans, Ans{ln.rmx + a[i], i, ln.r});if(i > 1) ans = max(ans, Ans{ln.prmx + rn.lmx, ln.rp, i});if(i < n) ans = max(ans, Ans{ln.rmx + rn.lpmx, i, rn.lp});// if(i == 4) cout << ln.prmx << " ?? " << ln.rp << endl;// cout << i << " " << ans.v << " " << ans.x << " " << ans.y << endl;}if(ans.x == ans.y) ans.x = 1, ans.y = n;cout << ans.v << endl;cout << ans.x << " " << ans.y << endl;return 0;
}

我写的另一种比较烦的做法,可以用来练习。枚举 O(n2)O(n^2)O(n2) 个子段和,考虑最大化答案的情况,即内部找一个最小值与外部的最大值交换。考虑与子段内与左边交换的情况,另一种情况将序列反转后同理。枚举 rrr,求 max⁡l=1r{∑i=lrai+max⁡i=1l−1ai−min⁡i=lr}\max\limits_{l = 1}^{r}\{\sum\limits_{i = l}^{r} a_i + \max\limits_{i = 1}^{l - 1} a_i - \min\limits_{i = l}^{r}\}l=1maxr​{i=l∑r​ai​+i=1maxl−1​ai​−i=lminr​},迭代 rrr,用线段树维护该值:r−1r-1r−1 到 rrr 时,对于 ∑i=lrai\sum\limits_{i = l}^{r} a_ii=l∑r​ai​ 这一项,只需要对 [1,r][1, r][1,r] 加上 ara_rar​;最大值项对应一次单点加;最小值项用单调栈维护,每次修改为区间加法。

#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define sz(a) ((int)a.size())
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e5 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;typedef pair<ll, int> pli;
const ll oo = 1ll << 60;
struct Node{ll val; int x, y;bool operator < (const Node &o) const{return val < o.val;}
} ans1, ans2;
ll a[maxn], b[maxn], sum[maxn]; pli mx[maxn];
pli stk[maxn]; int top;
int n;struct SegTree{pli mx[maxn << 2], mn[maxn << 2]; ll add[maxn << 2];void pushUp(int rt){mx[rt] = max(mx[lson], mx[rson]);mn[rt] = min(mn[lson], mn[rson]);}void build(int l, int r, int rt){add[rt] = 0;if(l == r){mx[rt] = mn[rt] = {0, l};return;}int mid = gmid;build(l, mid, lson);build(mid + 1, r, rson);pushUp(rt);}void pushDown(int rt){if(add[rt]){add[lson] += add[rt], add[rson] += add[rt];mx[lson].first += add[rt], mx[rson].first += add[rt];mn[lson].first += add[rt], mn[rson].first += add[rt];add[rt] = 0;}}void update(int l, int r, int rt, int L, int R, ll val){if(l >= L && r <= R){add[rt] += val;mx[rt].first += val;mn[rt].first += val;return;}int mid = gmid; pushDown(rt);if(L <= mid) update(l, mid, lson, L, R, val);if(R > mid) update(mid + 1, r, rson, L, R, val);pushUp(rt);}pli queryMx(int l, int r, int rt, int L, int R){if(l >= L && r <= R) return mx[rt];int mid = gmid; pli ret = {-oo, 0}; pushDown(rt);if(L <= mid) ret = max(ret, queryMx(l, mid, lson, L, R));if(R > mid) ret = max(ret, queryMx(mid + 1, r, rson, L, R));return ret;}pli queryMn(int l, int r, int rt, int L, int R){if(l >= L && r <= R) return mn[rt];int mid = gmid; pli ret = {oo, 0}; pushDown(rt);if(L <= mid) ret = min(ret, queryMn(l, mid, lson, L, R));if(R > mid) ret = min(ret, queryMn(mid + 1, r, rson, L, R));return ret;}
} tr_a, tr_sum, tr;void solve(Node &ans){sum[0] = 0, mx[0] = {-oo, 0};for(int i = 1; i <= n; ++i){sum[i] = sum[i - 1] + a[i];mx[i] = max(mx[i - 1], pli{a[i], i});}stk[top = 0] = {-oo, 0};tr_a.build(1, n, 1);tr_sum.build(1, n, 1);tr.build(1, n, 1);for(int i = 1; i <= n; ++i){tr_a.update(1, n, 1, i, i, a[i]);tr_sum.update(1, n, 1, 1, i, a[i]);tr.update(1, n, 1, 1, i, a[i]);tr.update(1, n, 1, i, i, mx[i - 1].first - a[i]);while(a[i] <= stk[top].first){pli er = stk[top--], el = stk[top];tr.update(1, n, 1, el.second + 1, er.second, er.first - a[i]);}stk[++top] = {a[i], i};pli e = tr_sum.queryMx(1, n, 1, 1, i);ll s = sum[i]; int l = e.second;Node tmp = Node{s, l, i};if(ans < tmp) ans = tmp;if(i == 1) continue;e = tr.queryMx(1, n, 1, 2, i);s = e.first, l = e.second;int pl = mx[l - 1].second, pr = tr_a.queryMn(1, n, 1, l, i).second;tmp = Node{s, pl, pr};if(ans < tmp) ans = tmp;}
}int main(){ios::sync_with_stdio(0); cin.tie(0);cin >> n;for(int i = 1; i <= n; ++i) cin >> a[i];ans1.val = ans2.val = -oo;solve(ans1);reverse(a + 1, a + 1 + n);solve(ans2);ans2.x = n - ans2.x + 1;ans2.y = n - ans2.y + 1;if(ans1 < ans2) ans1 = ans2;if(ans1.x == ans1.y) ans1.x = 1, ans1.y = n;cout << ans1.val << endl;cout << ans1.x << " " << ans1.y << endl;return 0;
}

G - Moore’s Law

简要题意:

给定 nnn,构造一个数 xxx 满足 xxx 十进制表示仅包含 111 和 222,且 xxx 是 2n2^n2n 的倍数。

解题思路:

递推构造,ans1=2ans_1 = 2ans1​=2,对于 i>1i \gt 1i>1,讨论 ansi−1%2ians_{i - 1} \%~ 2^iansi−1​% 2i,若余数为 2i−12^{i - 1}2i−1,则加上 10i−110^{i - 1}10i−1 使得余数为 000;若余数为 000,可不操作,或加上 2×10i−12×10^{i - 1}2×10i−1。

参考代码:
ans = [0 for i in range(43)]
ans[1] = '2'
for i in range(2, 43):if int(ans[i - 1]) % 2**i == 0:ans[i] = '2' + ans[i - 1]else:ans[i] = '1' + ans[i - 1]
n = int(input())
print(ans[n])

I - Number builder

简要题意:

签到题。

解题思路:

分类讨论。

参考代码:
#include<bits/stdc++.h>
using namespace std;
#define pb emplace_back
#define sz(a) ((int)a.size())
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
typedef long long ll;
typedef pair<int, int> pii;
const int maxn = 1e2 + 5;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;int main(){ios::sync_with_stdio(0); cin.tie(0);int n; cin >> n;int s = n % 3 == 1 ? 1 : 2;do{cout << s;n -= s, s = 3 - s;}while(n > 0);cout << endl;return 0;
}

2016-2017 7th BSUIR Open Programming Contest. Final 补题相关推荐

  1. B-Traveling Salesman Problem[CF-Gym-102134][2016-2017 7th BSUIR Open Programming Contest]

    原题传送门 题面 Traveling Salesman Problem time limit per test2 secondsmemory limit per test64 megabytesinp ...

  2. 2017 ACM Arabella Collegiate Programming Contest div2的题,部分题目写个题解

    F. Monkeying Around   维护点在多少个线段上 http://codeforces.com/gym/101350/problem/F 题意:有m个笑话,每个笑话的区间是[L, R], ...

  3. 2019-2020 10th BSUIR Open Programming Championship. Semifinal 补题

    B. BSUIR Open X 从nnn个字符串中任选两个进行拼接,求拼接成"BSUIROPENX"的方法数. 思路: 首先统计各字符串的出现次数, 再对"BSUIROP ...

  4. 2016 China Collegiate Programming Contest Final

    2016 China Collegiate Programming Contest Final Table of Contents 2016 China Collegiate Programming ...

  5. 2016, IX Samara Regional Intercollegiate Programming Contest I. Deadline

    2016, IX Samara Regional Intercollegiate Programming Contest I. Deadline 题目看这里 Alex works as a devel ...

  6. (寒假开黑gym)2018 ACM-ICPC, Syrian Collegiate Programming Contest(爽题)

    layout: post title: (寒假开黑gym)2018 ACM-ICPC, Syrian Collegiate Programming Contest(爽题) author: " ...

  7. 2015 ACM Arabella Collegiate Programming Contest(F题)

    F. Palindrome [ Color: Pink ] A string is palindrome if it can be read the same way in either direct ...

  8. the 12th UESTC Programming Contest Final Justice is Given by Light (几何+ 二分)

    题目来源: http://acm.uestc.edu.cn/#/problem/show/814 题意:是给你一堆凸包上的点,这些点会形成一个凸多边形,有两个god站在这个多边形上,他们可以释放一个半 ...

  9. 2017 ACM Jordanian Collegiate Programming Contest

    A. Chrome Tabs 当$n=1$时答案为$0$,当$k=1$或$k=n$时答案为$1$,否则答案为$2$. #include<cstdio> int T,n,k; int mai ...

最新文章

  1. MAX487制作RS485总线接口模块
  2. Tomcat 7 安装成功,启动后显示空白页问题
  3. JNDI数据源的连接属性
  4. Java的知识点26——File_API
  5. 怎么计算末年某月某天有几个星期天公司
  6. css3浏览,css3支持哪些浏览器?
  7. 一步一步写算法(之图添加和删除)
  8. Luogu2024[NOI2001] 食物链
  9. websoc是什么可以卸载吗_Win7系统中unity web player是什么程序?能否卸载
  10. Linux 硬盘读写测速
  11. 免费易用的Web版OFD阅读器
  12. 概念区分:灰度发布、蓝绿发布、滚动发布
  13. ps cs6安装教程
  14. pycharm 配置虚拟环境 安装虚拟环境
  15. 迄今见过的最好的职业规划文章
  16. 嵌入式系统开发笔记89:认识AVR微控制器系统架构
  17. C语言-小写转换大写
  18. ES6中Set方法实现数组去重
  19. 无限循环的二进制小数怎么精确转换为十进制小数
  20. 全年营收预增40%,奈雪的茶背后的喜与忧

热门文章

  1. java去除图片水印的解决办法
  2. 有生之年转ta系列4pc手机图形api介绍
  3. DeepMind再爆性骚扰丑闻!内部邮件泄露,色狼自夸猛男
  4. B. Alyona and a Narrow Fridge
  5. 计算机对逻辑算符的运算次序,逻辑运算符的优先顺序
  6. 基于环信视频语音通话功能
  7. Alphapose - Windows下Alphapose(Pytorch 1.1+)版本2021最新环境配置步骤以及踩坑说明
  8. Java面向对象基础呕心沥血三千字
  9. 机器学习——XGboost模型
  10. 正则表达式中级应用(java语言版)