2014 Benelux Algorithm Programming Contest (BAPC 14) 部分题解
来源:互联网 发布:淘宝优惠群公告怎么写 编辑:程序博客网 时间:2024/05/22 03:23
太弱了。只能做一半
B - Button Bashing (bfs)
题意
问调到目标值的最小步,不然就输出最接近的。
思路
一开始不知道怎么就想到DP去了,先DP出正的,然后DP负的,还一直以为这样是对的。
bfs搞搞。
代码
#include <stack>#include <cstdio>#include <list>#include <cassert>#include <set>#include <fstream>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>//#pragma comment(linker, "/STACK:102400000,102400000")#include <string>#include <map>#include <cmath>//#include <ext/pb_ds/assoc_container.hpp>//#include <ext/pb_ds/hash_policy.hpp>using namespace std;//using namespace __gnu_pbds;#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define X first#define Y second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define FOR(i, a, b) for (int i=(a); (i) < (b); (i)++)#define FOOR(i, a, b) for (int i = (a); (i)<=(b); (i)++)const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;const double eps = 1e-4;const int MAXN = 3e5+10;const int MOD = 10007;const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };const int seed = 131;int cases = 0;typedef pair<int, int> pii;queue<pii> Q;int vis[10000], tar;vector<int> arr;void bfs(){ Q.push({0, 0}); while (!Q.empty()) { pii u = Q.front(); Q.pop(); for (int i = 0; i < SZ(arr); i++) { int v = u.X + arr[i]; if (v > 3600) v = 3600; if (vis[v] != INF || v <= 0) continue; vis[v] = u.Y+1; Q.push({v, u.Y+1}); } } if (vis[tar] != INF) printf("%d 0\n", vis[tar]); else for (int i = tar+1; i <= 3600; i++) if (vis[i] != INF) { printf("%d %d\n", vis[i], i-tar); return; }}int main(){ //ROP; //freopen("out.txt", "w", stdout); int T; scanf("%d", &T); while (T--) { arr.clear(); MS(vis, INF); vis[0] = 0; int n; scanf("%d%d", &n, &tar); for (int i = 0; i < n; i++) { int tmp; scanf("%d", &tmp); arr.PB(tmp); } bfs(); } return 0;}
E - Excellent Engineers (线段树)
题意
如果一个人rank都比另一个人高,就可以干掉另一个人。
问最后有多少人能存活。
思路
显然最后存活的数和输入顺序无关。
假设三个属性分别为x、y、z。
我们可以先按x排序。
线段树的区间表示的是y,线段树维护的是某个范围内的y对应z的最小值。
之后假设我们现在要插入第x个人。
显然他不能消灭掉前x-1个人,因为前面人至少x的rank比他高。所以我们考虑他能不能存活下来。
假设第x个人的y=y0, z=z0。
如果存在一个人,使得
所以我们可以在线段树的(1~y0-1)区间内查询它的最小值,如果最小值
代码
#include <stack>#include <cstdio>#include <list>#include <cassert>#include <set>#include <fstream>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>//#pragma comment(linker, "/STACK:102400000,102400000")#include <string>#include <map>#include <cmath>//#include <ext/pb_ds/assoc_container.hpp>//#include <ext/pb_ds/hash_policy.hpp>using namespace std;//using namespace __gnu_pbds;#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define X first#define Y second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define FOR(i, a, b) for (int i=(a); (i) < (b); (i)++)#define FOOR(i, a, b) for (int i = (a); (i)<=(b); (i)++)const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;const double eps = 1e-4;const int MAXN = 1e5+10;const int MOD = 10007;const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };const int seed = 131;int cases = 0;typedef pair<int, int> pii;struct POINT{ int x, y, z; bool operator < (const POINT &a) const { return x < a.x; }}p[MAXN];struct TREE{ int min_val;}t[MAXN<<2];void push_up(int rt){ t[rt].min_val = min(t[LRT].min_val, t[RRT].min_val);}void Update(int rt, int l, int r, int y, int z){ if (l == r) { t[rt].min_val = z; return; } int mid = MID(l, r); if (y <= mid) Update(LC, y, z); else Update(RC, y, z); push_up(rt);}int Query(int rt, int l, int r, int L, int R){ int ret = INF; if (L <= l && r <= R) return t[rt].min_val; int mid = MID(l, r); if (L <= mid) ret = min(ret, Query(LC, L, R)); if (R >= mid+1) ret = min(ret, Query(RC, L, R)); return ret;}int main(){ //ROP; int T; scanf("%d", &T); while (T--) { MS(t, INF); int n; scanf("%d", &n); FOR(i, 0, n) scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].z); sort(p, p+n); int ans = 0; for (int i = 0; i < n; i++) { if (p[i].y != 1) { int tmp = Query(1, 1, n, 1, p[i].y-1); if (tmp < p[i].z) continue; } ans++; Update(1, 1, n, p[i].y, p[i].z); } printf("%d\n", ans); } return 0;}
I - Interesting Integers (扩展欧几里得)
题意
可以定义Fibonacci数列的前两项,现在给出n,问满足题目要求的最小的两项。
思路
先仰慕illuz巨菊!
一开始老是想着分解n成两项之和,一直没思路。
然后请教了hcbbt巨巨。
我们知道,<=1e9的Finobacci数列只有50项。而且每一项的系数都是Fibonacci数列。
假设系数是x、y。
那么我们就是求ax+by = n的最小a、b。
然后就可以用扩展欧几里得搞了。
又加深了对扩展欧几里得的理解= =
代码
#include <stack>#include <cstdio>#include <list>#include <cassert>#include <set>#include <fstream>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>//#pragma comment(linker, "/STACK:102400000,102400000")#include <string>#include <map>#include <cmath>//#include <ext/pb_ds/assoc_container.hpp>//#include <ext/pb_ds/hash_policy.hpp>using namespace std;//using namespace __gnu_pbds;#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define X first#define Y second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define FOR(i, a, b) for (int i=(a); (i) < (b); (i)++)#define FOOR(i, a, b) for (int i = (a); (i)<=(b); (i)++)const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;const double eps = 1e-4;const int MAXN = 3e5+10;const int MOD = 10007;const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };const int seed = 131;int cases = 0;typedef pair<LL, LL> pii;void extend_gcd(LL a, LL b, LL &d, LL &x, LL &y){ if (!b) d = a, x = 1, y = 0; else { extend_gcd(b, a%b, d, y, x); y -= x * (a/b); }}pii ans;void Solve(LL x, LL y, LL a, LL b){ LL k = -x / b; x += k*b, y -= k*a; if (x <= 0) { while (x <= 0) x += b, y -= a; if (y < x) return; } else { while (x - b > 0) x -= b, y += a; if (y < x) return; } k = (y-x-1) / (a+b); x += b*k, y -= a*k; while (y >= x && y <= ans.Y) { if (y < ans.Y || (y == ans.Y && x < ans.X)) ans.X = x, ans.Y = y; x += b, y -= a; }}int arr[200];int main(){ //ROP; int T; scanf("%d", &T); arr[1] = arr[2] = 1; for (int i = 3; i <= 50; i++) arr[i] = arr[i-1] + arr[i-2]; while (T--) { ans.X = INF, ans.Y = INF; int n; scanf("%d", &n); for (int i = 2; i <= 43; i++) { int a = arr[i-1], b = arr[i]; if (n % __gcd(a, b) != 0) continue; LL d, x, y; extend_gcd(a, b, d, x, y); a /= d, b /= d; x *= n, y *= n; Solve(x, y, a, b); } cout << ans.X << " " << ans.Y << endl; } return 0;}
J - Jury Jeopardy (模拟)
题意
让我们根据序列输出图。
思路
首先我们知道没有比起点更小的列。不然起点就会被封死。
模拟一下。先把所有的.给记上,然后记录一下行列的最大值和最小值,然后一排一排补全即可。
代码
#include <stack>#include <cstdio>#include <list>#include <cassert>#include <set>#include <fstream>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>//#pragma comment(linker, "/STACK:102400000,102400000")#include <string>#include <map>#include <cmath>//#include <ext/pb_ds/assoc_container.hpp>//#include <ext/pb_ds/hash_policy.hpp>using namespace std;//using namespace __gnu_pbds;#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define X first#define Y second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define FOR(i, a, b) for (int i=(a); (i) < (b); (i)++)#define FOOR(i, a, b) for (int i = (a); (i)<=(b); (i)++)const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;const double eps = 1e-4;const int MAXN = 300+10;const int MOD = 10007;//const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };const int seed = 131;int cases = 0;typedef pair<int, int> pii;struct DIRECTION{ pii f, b, l, r; int db, dl, dr;}dir[4];char mp[500][500];void init(){ //0上1下2左3右 dir[0].f = {-1, 0}, dir[0].b = {1, 0}, dir[0].l = {0, -1}, dir[0].r = {0, 1}; dir[1].f = {1, 0}, dir[1].b = {-1, 0}, dir[1].l = {0, 1}, dir[1].r = {0, -1}; dir[2].f = {0, -1}, dir[2].b = {0, 1}, dir[2].l = {1, 0}, dir[2].r = {-1, 0}; dir[3].f = {0, 1}, dir[3].b = {0, -1}, dir[3].l = {-1, 0}, dir[3].r = {1, 0}; dir[0].db = 1, dir[0].dl = 2, dir[0].dr = 3; dir[1].db = 0, dir[1].dl = 3, dir[1].dr = 2; dir[2].db = 3, dir[2].dl = 1, dir[2].dr = 0; dir[3].db = 2, dir[3].dl = 0, dir[3].dr = 1;}string str;void Solve(){ int x = 250, y = 250, cur = 3, ans = 0; int max_col = -1, max_row = -1, min_row = INF; for (int i = 0; i < SZ(str); i++) { max_col = max(max_col, y); max_row = max(max_row, x); min_row = min(min_row, x); assert(y >= 250); char c = str[i]; if (c == 'F') { mp[x+dir[cur].f.X][y+dir[cur].f.Y] = '.'; x += dir[cur].f.X, y += dir[cur].f.Y; } else if (c == 'B') { x += dir[cur].b.X, y += dir[cur].b.Y; mp[x][y] = '.'; cur = dir[cur].db; } else if (c == 'L') { x += dir[cur].l.X, y += dir[cur].l.Y; mp[x][y] = '.'; cur = dir[cur].dl; } else { x += dir[cur].r.X, y += dir[cur].r.Y; mp[x][y] = '.'; cur = dir[cur].dr; } } for (int i = 250; i <= max_col+1; i++) for (int j = min_row-1; j <= max_row+1; j++) mp[j][i] = (mp[j][i] == '.' ? '.' : '#'); printf("%d %d\n", max_row-min_row+3, max_col+2-250); for (int i = min_row-1; i <= max_row+1; i++) printf("%s\n", mp[i]+250);}int main(){ //ROP; init(); int T; scanf("%d", &T); printf("%d\n", T); while (T--) { MS(mp, 0); cin >> str; Solve(); } return 0;}
K - Key to Knowledge (中途相遇法 + 状态压缩)
题意
给出n个01串,每个01串后面有个数字,代表正确的个数。问正确的答案有几种。如果只有一种输出。
思路
首先想到状态压缩,但是(1<<30)的规模显然要跪。
然后又想了一会儿中途相遇,想了一会儿,想不出相遇什么东西。
然后又YY了一些解法,还是想不出来。
然后就请教hcbbt巨巨。
然后他想到了枚举少的一方的状态然后暴力。我一听也觉得可以。然而我们都以为那时候的状态是
直到我敲完代码调试的时候才发现,那样状态是很多的( TДT)
然后就看了题解。
正解是用中途相遇法。
我们可以通过枚举前m/2位的正确答案的个数,然后得到这种情况下各串后面剩下的位需要多少个正确的答案,存在map里。
然后我们枚举剩下部分的正确答案个数。在map里找是不是有一模一样的。如果是的话,说明这部分的正确答案和以前那部分的正确答案是可以拼起来的,也就是完整的答案。
本来这个过程是O(nlogn)的,但是因为n比较小,可以直接按进制hash成一个数字,这样就变成了O(logn)。
学习了红名爷玄幻的代码。。。
代码
#include <stack>#include <cstdio>#include <list>#include <cassert>#include <set>#include <fstream>#include <iostream>#include <string>#include <vector>#include <queue>#include <functional>#include <cstring>#include <algorithm>#include <cctype>//#pragma comment(linker, "/STACK:102400000,102400000")#include <string>#include <map>#include <cmath>//#include <ext/pb_ds/assoc_container.hpp>//#include <ext/pb_ds/hash_policy.hpp>using namespace std;//using namespace __gnu_pbds;#define LL long long#define ULL unsigned long long#define SZ(x) (int)x.size()#define Lowbit(x) ((x) & (-x))#define MP(a, b) make_pair(a, b)#define MS(arr, num) memset(arr, num, sizeof(arr))#define PB push_back#define X first#define Y second#define ROP freopen("input.txt", "r", stdin);#define MID(a, b) (a + ((b - a) >> 1))#define LC rt << 1, l, mid#define RC rt << 1|1, mid + 1, r#define LRT rt << 1#define RRT rt << 1|1#define FOR(i, a, b) for (int i=(a); (i) < (b); (i)++)#define FOOR(i, a, b) for (int i = (a); (i)<=(b); (i)++)const double PI = acos(-1.0);const int INF = 0x3f3f3f3f;const double eps = 1e-4;const int MAXN = 3e5+10;const int MOD = 10007;const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };const int seed = 131;int cases = 0;typedef pair<int, int> pii;struct POINT{ string str; int ans;}p[20];map<LL, int> mp;LL hsh[1<<16];int m, n;void Solve(){ mp.clear(); for (int sta = 0; sta < (1<<m/2); sta++) { LL x = 0; bool ok = true; for (int i = 0; i < n; i++) { int cur_ans = p[i].ans; for (int j = 0; j < m/2; j++) if ((p[i].str[j] == '1') == ((sta>>j)&1)) //如果出现了一个正确答案 cur_ans--; if (cur_ans < 0) ok = false; x = x * (m+1) + cur_ans; } if (!ok) x = -1; hsh[sta] = x; mp[x]++; } int ans_num = 0, ans = -1; for (int sta = 0; sta < (1<<(m-m/2)); sta++) { LL x = 0; for (int i = 0; i < n; i++) { int cur_ans = 0; for (int j = m/2; j < m; j++) if ((p[i].str[j] == '1') == ((sta>>(j-m/2)&1))) cur_ans++; x = x * (m+1) + cur_ans; } ans_num += mp[x]; if (ans == -1 && mp[x] > 0) { for (int i = 0; i < (1<<(m/2)); i++) if (x == hsh[i]) ans = i + (sta<<(m/2)); } } if (ans_num != 1) printf("%d solutions\n", ans_num); else { for (int i = 0; i < m; i++) printf("%d", (ans>>i)&1); puts(""); }}int main(){ //ROP; int T; scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) cin >> p[i].str >> p[i].ans; Solve(); } return 0;}
- 2014 Benelux Algorithm Programming Contest (BAPC 14) 部分题解
- 2014 Benelux Algorithm Programming Contest (BAPC 14)
- 2014 Benelux Algorithm Programming Contest (BAPC 14) K
- 2007 Benelux Algorithm Programming Contest (BAPC 2007) A
- BAPC 2016 The 2016 Benelux Algorithm Programming Contest-----L Sticky Situation
- BAPC 2016 The 2016 Benelux Algorithm Programming Contest------I: Older Brother
- The 2006 Benelux Algorithm Programming Contest 解题报告
- Zhejiang Provincial Programming Contest 2007 部分题解
- The 5th Zhejiang Provincial Collegiate Programming Contest 部分题解
- The 13th Zhejiang Provincial Collegiate Programming Contest 部分题解
- 2016 ACM Amman Collegiate Programming Contest 训练赛部分题解
- 【bfs && 如何想到bfs】2014 Benelux Algorithm B
- Programming Contest Ranking(题解)
- The 2015 ACM-ICPC China Shanghai Metropolitan Programming Contest部分题解
- The 2014 ACM-ICPC Asia Mudanjiang Regional Contest 【部分题解】
- The 2013 Arab Collegiate Programming Contest 题解
- programming-challenges Contest Scoreboard (110207) 题解
- 2017 Wuhan University Programming Contest 题解
- openwrt 编译命令记录
- arm-linux-gdb调试工具的安装与交叉编译gdbserver
- Matlab函数速查
- android线程池
- java监听器
- 2014 Benelux Algorithm Programming Contest (BAPC 14) 部分题解
- 神经网络与机器学习笔记——K-均值聚类
- 递归算法详解
- IDF实验室:百密一疏--孔子的学费
- Matlab与c语言混合编程接口方法
- android 多线程 - 线程池 Executors.newFixedThreadPool 的使用例子
- iTOP4412裸机开发——LED
- Android平台下基于XMPP的IM研究
- 白岩松:爱你现在的时光