2016-2017 7th BSUIR Open Programming Contest. Final 补题
题目链接
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∑pai,其中 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,求 maxl=1r{∑i=lrai+maxi=1l−1ai−mini=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∑rai+i=1maxl−1ai−i=lminr},迭代 rrr,用线段树维护该值:r−1r-1r−1 到 rrr 时,对于 ∑i=lrai\sum\limits_{i = l}^{r} a_ii=l∑rai 这一项,只需要对 [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 补题相关推荐
- 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 ...
- 2017 ACM Arabella Collegiate Programming Contest div2的题,部分题目写个题解
F. Monkeying Around 维护点在多少个线段上 http://codeforces.com/gym/101350/problem/F 题意:有m个笑话,每个笑话的区间是[L, R], ...
- 2019-2020 10th BSUIR Open Programming Championship. Semifinal 补题
B. BSUIR Open X 从nnn个字符串中任选两个进行拼接,求拼接成"BSUIROPENX"的方法数. 思路: 首先统计各字符串的出现次数, 再对"BSUIROP ...
- 2016 China Collegiate Programming Contest Final
2016 China Collegiate Programming Contest Final Table of Contents 2016 China Collegiate Programming ...
- 2016, IX Samara Regional Intercollegiate Programming Contest I. Deadline
2016, IX Samara Regional Intercollegiate Programming Contest I. Deadline 题目看这里 Alex works as a devel ...
- (寒假开黑gym)2018 ACM-ICPC, Syrian Collegiate Programming Contest(爽题)
layout: post title: (寒假开黑gym)2018 ACM-ICPC, Syrian Collegiate Programming Contest(爽题) author: " ...
- 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 ...
- the 12th UESTC Programming Contest Final Justice is Given by Light (几何+ 二分)
题目来源: http://acm.uestc.edu.cn/#/problem/show/814 题意:是给你一堆凸包上的点,这些点会形成一个凸多边形,有两个god站在这个多边形上,他们可以释放一个半 ...
- 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 ...
最新文章
- MAX487制作RS485总线接口模块
- Tomcat 7 安装成功,启动后显示空白页问题
- JNDI数据源的连接属性
- Java的知识点26——File_API
- 怎么计算末年某月某天有几个星期天公司
- css3浏览,css3支持哪些浏览器?
- 一步一步写算法(之图添加和删除)
- Luogu2024[NOI2001] 食物链
- websoc是什么可以卸载吗_Win7系统中unity web player是什么程序?能否卸载
- Linux 硬盘读写测速
- 免费易用的Web版OFD阅读器
- 概念区分:灰度发布、蓝绿发布、滚动发布
- ps cs6安装教程
- pycharm 配置虚拟环境 安装虚拟环境
- 迄今见过的最好的职业规划文章
- 嵌入式系统开发笔记89:认识AVR微控制器系统架构
- C语言-小写转换大写
- ES6中Set方法实现数组去重
- 无限循环的二进制小数怎么精确转换为十进制小数
- 全年营收预增40%,奈雪的茶背后的喜与忧