Mutual Training for Wannafly Union #3 & 4
我不知道我以后还记不记得补题。。。我只能尽量当天睡觉前能补多少就补多少,时间总是不够用,脑子更不够用orz
题目链接:https://vjudge.net/contest/159576#overview
A - Dungeon Trap [ UVALive – 7220 ] 【最短路bfs】
//yy:练题时都没看这题,看题目就以为很难。。。晚上补 的时候发现居然是最短路,奥妙重重。。。
题意:0表示障碍,要将非0数转化成0(会花费这个数的值)使得A和B不连通(该题连通为四连通),问最大花费多少。
看着题解做的,枚举最后一个放置障碍的点,则ans=max(ans,sum-(从A到这个点的距离+从B到这个点的距离-2*这个点的权值));
//补题:AC by lyy:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cmath> #include<queue> #include<limits.h> #define CLR(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef long long ll; const int N = 105; const int inf = 0x3f3f3f3f; int n, m; int sum; int dx[] = {1,0,-1,0}; int dy[] = {0,1,0,-1}; char s[N][N]; int d[N][N][2]; int ans; int ax, ay, bx, by; bool check(int x, int y) { if(x < 0 || x >= n || y < 0 || y >= m) return false; if(s[x][y] == '0') return false; return true; } struct node { int x, y; }; void bfs(int x, int y, int id) { queue<node> q; d[x][y][id] = 0; q.push(node{x, y}); while(!q.empty()) { node t = q.front(); q.pop(); for(int i = 0; i < 4; ++i) { int xx = t.x + dx[i]; int yy = t.y + dy[i]; int w = s[xx][yy]-'0'; if(check(xx, yy)) { if(d[xx][yy][id] > d[t.x][t.y][id] + w) { d[xx][yy][id] = d[t.x][t.y][id] + w; q.push(node{xx, yy}); } } } } } int main(){ int t; int i, j, k; scanf("%d",&t); for(k = 1; k <= t; ++k) { CLR(d, inf); scanf("%d%d", &n, &m); sum = 0; for(i = 0; i < n; ++i) { scanf("%s", s[i]); for(j = 0 ; j < m; ++j) { if(s[i][j] == 'A') { ax = i; ay = j; } else if(s[i][j] == 'B') { bx = i; by = j; } else { sum += s[i][j] - '0'; } } } bfs(ax, ay, 0); bfs(bx, by, 1); ans = 0; for(i = 0; i < n; ++i) { for(j = 0; j < m; ++j) { if(s[i][j] >= '1' && s[i][j] <= '9') { if(d[i][j][0] != inf && d[i][j][1] != inf) { int c = s[i][j] - '0'; ans = max(ans, sum-d[i][j][0]-d[i][j][1]+2*c); ] } } } printf("Case #%d: %d ", k, ans); } return 0; }
B - Pigeonhole Tower [ SPOJ – PHT ] 【二分】
题意:求用n根木棒能搭出多少层
第一层3根,第二层5,第三层7.。。。2*n+1.。。。。。。二分数量
//AC by lwq:
#include<stdio.h> #include<algorithm> using namespace std; long long int q[1000000]; int main() { int T; scanf("%d",&T); q[1]=3; int t=0; for(int i=2;i<=1000000;i++) { q[i]=q[i-1]+2*i+1; } while(T--) { t++; long long int n; scanf("%lld",&n); long long int L=1; long long int R=1000000; long long int MID=(L+R)/2; while(L+1<R) { if(n>=q[MID]) { L=MID; } else R=MID; MID=(L+R)/2; } if(n<3) MID=0; printf("Case %d: %lld ",t,MID); // printf("%") } return 0; }
C - Interesting Numbers [ SPOJ – INUM ] 【二分】
题意:求分别有几对数满足差值绝对值最大和最小。
//AC by kn:
#include <iostream> #include <cstdio> #include <cmath> #include <climits> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5 + 100; ll a[maxn]; int main() { int n; cin >> n; for(int i = 0; i < n; ++i) { cin >> a[i]; } ll mi = LONG_LONG_MAX; ll ma = LONG_LONG_MIN; sort(a, a + n); for(int i = 1; i < n; ++i) { mi = min(mi, a[i] - a[i - 1]); } ma = a[n - 1] - a[0]; ll ans_mi = 0; ll ans_ma = 0; for(int i = 0; i < n; ++i) { ans_mi += (upper_bound(a + i + 1, a + n, a[i] + mi) - lower_bound(a + i + 1, a + n, a[i] + mi)); ans_ma += (upper_bound(a + i + 1, a + n, a[i] + ma) - lower_bound(a + i + 1, a + n, a[i] + ma)); } //cout << mi << " " << ma << endl; cout << ans_mi << " " << ans_ma << endl; return 0; } /* 5 0 0 2 0 0 */
D – SubXor [SPOJ – SUBXOR]
//yy:讨论了一会儿,我猜要用前缀树什么的,要不然超时,,然后大家都不会数据结构,然后就没有然后了orz,改天再补。。。
E – Guards [UVALive – 5813]
//yy:就看懂了题意,没想出思路orz,很好玩,看题目发现构成一个矩形时就是一个集合,其他又是一个集合,然后想搜索,不会,也想不出怎么安排棋子;想了找规律,感觉也找不到;想了图论,也没想出什么,毕竟图论我感觉自己连基本概念都很多不知道;想了DP然后就不敢再想了。。。。放弃orz,改天补。。。
F - Extremely Lagged Fibonacci [SPOJ – EXLAGFIB]
//yy:感觉太数学,再次放弃,害怕orz
G - Smile House [CodeForces – 147B]
//yy:我看完这题突然想到floyd,dp之类的,但是不知道具体怎么处理,又放弃了orz,改天再补
H - Renting Bikes [CodeForces – 363D] 【贪心,二分】
题意:已知每辆车的价格和人有的钱数和共享资金,每人最多买一辆车,问最多能买多少车以及私人花费的最多钱数。
题解:二分买车的数量,用最有钱的mid个人买最便宜的mid辆车。
//yy:二分折腾了好久orz结果最后细节没处理好一直WA,,二分求和时忘记改long long了。。
补题:AC by lyy:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cmath> #include<queue> #include<limits.h> #define CLR(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef long long ll; const int N = 1e5+5; int n, m, k; int a[N], b[N]; bool cmp(int x, int y) { return x > y; } int main(){ int i, j; scanf("%d%d%d", &n, &m, &k); for(i = 0; i < n; ++i) scanf("%d", &a[i]);//人有的钱 for(i = 0; i < m; ++i) scanf("%d", &b[i]);//车的价格 sort(a, a+n, cmp); sort(b, b+m); int l = 0, r = min(n, m); while(l < r) {//二分买车的数量 int mid = (l + r + 1) >> 1; ll s = 0; for(int i = 0; i < mid; ++i) { if(a[i] < b[mid-1-i]) { s += b[mid-1-i] - a[i]; } } if(s > k) r = mid-1; else l = mid; } printf("%d ", r); ll s = 0; for(i = 0; i < r; ++i) { s += b[i]; } s -= k; if(s < 0) s = 0; printf("%lld ", s); return 0; }
I - Greg's Workout [CodeForces – 255A] 【水题】
//AC by lyy:我觉得自己好水啊、、、
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cmath> #include<queue> #include<limits.h> #define CLR(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef long long ll; const int N = 1e5; const int mod = 1e9+7; int a[30]; int main() { int n; scanf("%d", &n); int i, j; int x = 0, y = 0, z = 0; for(i = 0; i < n; ++i) { scanf("%d", &a[i]); if(i % 3 == 0) {x += a[i];} else if(i % 3 == 1) {y+=a[i];} else z+=a[i]; } if(x >= y ) { printf("%s ", x > z ? "chest" : "back"); } else printf("%s ", y > z ? "biceps" : "back"); return 0; }
J - MUH and Cube Walls [CodeForces – 471D] 【KMP】
题解:将幅度记录(就是相邻两数的差值),再KMP。
//AC by lyy:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cmath> #include<queue> #include<limits.h> #define CLR(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef long long ll; const int N = 2e5+5; const int mod = 1e9+7; double eps = 1e-8; int n, m; int ans; int a[N], b[N]; int nex[N]; void Next() { int i, j; j = nex[0] = -1; i = 0; while(i < m) { while(-1 != j && b[i] != b[j]) j = nex[j]; nex[++i] = ++j; } } void kmp(){ int i = 0, j = 0; Next(); while(i < n){ if(j == -1 || a[i] == b[j]){ i++; j++; } else j = nex[j]; if(j == m) { ans++; } } } int main(){ int i, j; scanf("%d%d", &n, &m); for(i = 0; i < n; ++i) scanf("%d", &a[i]); for(i = 0; i < m; ++i) scanf("%d", &b[i]); if(m == 1) { printf("%d ", n); return 0; } for(i = 0; i < n-1; ++i) { a[i] = a[i+1] - a[i]; } for(j = 0; j < m-1; ++j) { b[j] = b[j+1] - b[j]; } ans = 0; --n, --m; kmp(); printf("%d ", ans); return 0; }
K – Reclamation [CodeForces – 325D] 【并查集】
//yy:kn说这题他去年听学姐讲过但是没在意听,然后开始想思路,说先在右边加上最左边一列,再在两边设两个源点并分别把两边的格子连接,然后每放一个障碍就检查其周围八个格子是否有跟两个源点连接,如果有就不能放这个障碍……总之就是,只要障碍左右都连通了,那么圆柱的上顶和下底就会不连通,就不能放这个障碍,,然后他敲了发并查集没过,然后我们又挂了orz
L - Crazy Town [CodeForces – 499C] 【几何】
题意:有很多直线会把平面划分成很多块,给出直线方程的系数,起点和终点坐标,问最少走过几块可以从起点到终点
题解:分别把起点和终点代入每个直线方程,判断两点是否在直线两侧,是的话答案加一。
//yy:把long long改成了double就过了、、水题我总能以各种姿势先WA一下。。
AC by lyy:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<cmath> #include<queue> #include<limits.h> #define CLR(a,b) memset((a),(b),sizeof((a))) using namespace std; typedef long long ll; const int N = 1e5; const int mod = 1e9+7; double eps = 1e-8; double x1, y1, x2, y2; int main() { int n; scanf("%lf%lf%lf%lf", &x1, &y1, &x2, &y2); scanf("%d", &n); int ans = 0; while(n--) { double a, b, c; scanf("%lf%lf%lf", &a, &b, &c); if((a*x1+b*y1+c) * (a*x2+b*y2+c) < eps) ans++; } printf("%d ", ans); return 0; }