2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)【solved:12 / 13】
来源:互联网 发布:反转链表 非递归 java 编辑:程序博客网 时间:2024/06/07 11:38
A.Alphabet(LIS变形)
题意:
给你一个字符串,问你最少添加几个字符使得它能够存在一个子序列“abcdefg...xyz”。
数据:
长度不超过50。
思路:
我们枚举每一个字符ch作为起点,求一个LIS,是不是就得到了一个“abcdefg...xyz”的子串,然后填补上ch之前缺失的部分是不是就行了。答案就是min{26-len(LIS)}。复杂度O(n * n lg n)。
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1e5 + 5;int main(){ int a[55]; char s[55]; gets(s); int len = strlen(s); int ans = 0x3f3f3f3f; for(int i = 0; i < len;i++) { a[i] = s[i] - '0'; } int dp[55]; for(int i = 0; i < len; i++) { memset(dp, 0x3f3f3f3f, sizeof(dp)); for(int j = i; j < len; j++) { int pos = lower_bound(dp, dp + len, a[j]) - dp; dp[pos] = a[j]; } int temp = 26 - (lower_bound(dp, dp + len, 0x3f3f3f3f) - dp); ans = min(ans, temp); } printf("%d\n", ans); return 0;}
B.Barbells(暴力三进制枚举)
题意:
给你n个杠铃,m个杠铃的片,问你能组合出哪些杠铃(前提:左右杠铃片的质量相等),求出distinct的杠铃的重量。
数据:
n和m不超过14,杠铃和杠铃片的质量不超过1e8.
思路:
每个杠铃片有三种状态,放在左边,放在右边,不放。我们暴力枚举一下就行了,非常简单。O(3^m)。
#include<bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 20;LL b[maxn], p[maxn];int main(){ int n, m; scanf("%d%d", &n, &m); int stateMax = 1; for(int i = 0; i < m; i++) { stateMax *= 3; } for(int i = 0; i < n; i++) scanf("%lld", &b[i]); for(int i = 0; i < m; i++) scanf("%lld", &p[i]); sort(p, p + m); set<LL>ans; for(int S = 0; S < stateMax; S++) { int state = S; LL left = 0, right = 0; for(int i = 0; i < m; i++) { int f = state % 3; state /= 3; if(f == 0) left += p[i]; else if(f == 1) right += p[i]; else if(f == 3) continue; } if(left != right) continue; for(int i = 0; i < n; i++) { ans.insert(b[i] + left + right); } } for(auto o : ans) cout << o <<endl; return 0;}
C.Buggy Robot
题意:
大概就是你写一个up,down,left,right的指令,操控小机器人走出迷宫,然后如果机器人遇到的这条指令,是让它走到障碍物上的,它会跳过这条指令。如果机器人到达了终点,则所有剩余指令失效。你可以通过增加和删除指令,来使得机器人走到中间,问你至少需要修改几个指令。
数据:
迷宫的大小50*50。指令的长度是1-50。
思路:
大概就是一个spfa吧。dp[i][j][k]:(i, j)这个位置 下一步执行原指令的第k条的时候 需要增加的最少指令数。然后转移状态,如果这个状态和指令相同,idx++。
#include <bits/stdc++.h>using namespace std;const int INF = 0x3f3f3f3f;struct node{ int x, y, idx;};int n, m, sx, sy;int dp[55][55][55];//dp[i][j][k]:(i, j)这个位置 下一步执行原指令的第k条的时候 需要增加的最少指令数bool vis[55][55][55];char ma[55][55];char cmd[55];char dir[129];int dx[] = {-1, 1, 0, 0};int dy[] = {0, 0, -1, 1};int spfa(){ int ret = INF; memset(dp, INF, sizeof(dp)); queue<node>que; dp[sx][sy][0] = 0; que.push({sx, sy, 0}); while(que.size()) { node cur = que.front();que.pop(); vis[cur.x][cur.y][cur.idx] = 0; if(ma[cur.x][cur.y] == 'E') { ret = min(ret, dp[cur.x][cur.y][cur.idx]); continue; } for(int i = 0; i < 4; i++) { int fx = cur.x + dx[i], fy = cur.y + dy[i]; //如果越界或者走到了障碍物 那么skip这条指令。 if (fx < 1 || fx > n || fy < 1 || fy > m || ma[fx][fy] == '#') { if (dir[cmd[cur.idx]] == i) { if(dp[cur.x][cur.y][cur.idx] < dp[cur.x][cur.y][cur.idx + 1]) { dp[cur.x][cur.y][cur.idx + 1] = dp[cur.x][cur.y][cur.idx]; if (!vis[cur.x][cur.y][cur.idx + 1]) { vis[cur.x][cur.y][cur.idx + 1] = 1; que.push({cur.x, cur.y, cur.idx + 1}); } } } continue; } int ans = dp[cur.x][cur.y][cur.idx]; int fidx = cur.idx; if (dir[cmd[cur.idx]] == i) fidx++; else ans++; if (ans < dp[fx][fy][fidx]) { dp[fx][fy][fidx]= ans; if (!vis[fx][fy][fidx]) { vis[fx][fy][fidx] = 1; que.push({fx, fy, fidx}); } } } } return ret;}int main(){ memset(dir, -1, sizeof(dir)); dir['U'] = 0; dir['D'] = 1; dir['L'] = 2; dir['R'] = 3; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) { scanf("%s", ma[i] + 1); for(int j = 1; j <= m; j++) { if(ma[i][j] == 'R') sx = i, sy = j; } } scanf("%s", cmd); cout << spfa() << endl; return 0;}
D.Cameras(思维?)
题意:
数轴上1-n,你已经在其中k个位置有了标记,问你至少需要添加几个标记,使得任意连续r个位置,都至少有diff = 2个标记。
数据:
2<=n<=100000, 0 <= k <= n, 2 <= r <= n;
思路:
先把[1,r]区间填充的满足条件,然后每次挪动其实只要更改第一个和最后一个就行了,你们觉不觉得其实这个diff这个不是2,是3是4是5都行呀,只要<=r。这题可以随便改啊,这样O(n)就够了。
#include<bits/stdc++.h>using namespace std;const int diff = 2;int vis[100000 + 5];int main(){ int n, k, r; scanf("%d%d%d", &n, &k, &r); for(int i = 0; i < k; i++) { int x; scanf("%d", &x); vis[x] = 1; } int num = 0, ans = 0; for(int i = 1; i <= r; i++) { num += vis[i]; } ans += max(0, diff - num); for(int i = r; i >= 1; i --) { if(num == diff) break; if(!vis[i]) vis[i] = 1, num++; } //接下来可以保证每一个进入的区间[l,r]的前一个[l-1,r-1]都是满足diff这个条件的。因为每次只挪动1,所以只需要更改最后一个。 for(int nail = r + 1; nail <= n; nail++) { num = num - vis[nail - r] + vis[nail]; if(num < diff) vis[nail] = 1, ans++, num = diff; } printf("%d\n", ans); return 0;}
E.Contest Score(前缀和水题)
题意:
计算类似ACM的罚时呀,就是给你n个任务,然后你最多一口气能按顺序选前k个未完成的任务,然后挑最快的完成,重复至结束。问你罚时最短是多少。
数据:
n和k不超过300,每个任务时间不超过一百万。
思路:
水题。。维护个前缀和就行了。O(nlogn)
#include <bits/stdc++.h>using namespace std;int t[305];int main(){ int n, k; scanf("%d%d", &n, &k); for(int i = 0; i < n; i++) { scanf("%d", &t[i]); } priority_queue<int, vector<int>, greater<int>>que; int cnt = 0; while(cnt < k) que.push(t[cnt++]); long long sum = 0, ans = 0; while(que.size()) { sum += que.top();que.pop(); ans += sum; if(cnt < n) que.push(t[cnt++]); } printf("%lld\n", ans); return 0;}
F.Equality(....water)
#include <bits/stdc++.h>using namespace std;typedef long long LL;const int maxn = 1e5 + 5;int main(){ char s[15]; gets(s); int a, b, c; if(sscanf(s, "%d + %d = %d", &a, &b, &c) == 3) { if(a + b == c) puts("YES"); else puts("NO"); } return 0;}
G.Gravity(模拟)
#include <bits/stdc++.h>using namespace std;char ma[305][305];int main(){ int n, m; scanf("%d%d", &n, &m); for(int i = 1; i <= n; i++) scanf("%s", ma[i] + 1); for(int i = n - 1; i >= 0; i--) { for(int j = 1; j <= m; j++) { if(ma[i][j] != 'o') continue; int k = i; while(k + 1 <= n && ma[k + 1][j] == '.') k++; ma[i][j] = '.'; ma[k][j] = 'o'; } } for(int i = 1; i <= n; i++) printf("%s\n", ma[i] + 1); return 0;}
H.Islands(dfs联通块)
题意:
大概就是给你个图有陆地,水,陆地/水三种状态,然后问你最少有几块陆地,联通的算一块。
数据:
50 * 50的图。。很小
思路:
如果是陆地,开始dfs,dfs的过程中,只要非水就能继续。求个联通块数量就可以啦。
#include <bits/stdc++.h>using namespace std;int n, m;char ma[305][305];int vis[305][305];int dx[] = {0, 0, 1, -1};int dy[] = {1, -1, 0, 0};#define isInside(x, y) 0 <= x && x < n && 0 <= y && y < mvoid dfs(int x, int y){ vis[x][y] = 1; for(int i = 0; i < 4; i++) { int fx = x + dx[i], fy = y + dy[i]; if(isInside(fx, fy) && vis[fx][fy] == 0 && ma[fx][fy] != 'W') { dfs(fx, fy); } }}int main(){ scanf("%d%d", &n, &m); for(int i = 0; i < n; i++) { scanf("%s", ma[i]); } int ans = 0; for(int i =0; i < n; i++) { for(int j = 0; j < m; j++) { if(vis[i][j] == 0 && ma[i][j] == 'L') { dfs(i, j); ans++; } } } printf("%d\n", ans); return 0;}
I.Mismatched Socks(雀巢原理?)
题意:
给你n种不同的袜子的各自的数量。问你最多能配几对不同的袜子。
数据:
n不超过1000,ki不超过1e9。
思路:
雀巢原理?统计一下最多的袜子有几双,剩下的袜子有几双,其实就是一个雀巢原理的穿插的感觉吧。
其实复杂度可以O(n)的,只是看看这数据好水,才1000,懒得写max了,直接用堆了。
#include <bits/stdc++.h>using namespace std;typedef long long LL;int main(){ int n; scanf("%d", &n); LL preSum = 0; priority_queue<int>que; for(int i =0; i <n ;i++) { int x; scanf("%d", &x); que.push(x); preSum += x; } int maxx = que.top(); preSum -= maxx; if(preSum >= maxx) printf("%lld\n", (preSum + maxx) / 2); else printf("%lld\n", preSum); return 0;}
J.Postman(贪心?)
题意:
有一个邮差员要去n家送信,他每次只能带k封信。每一家的坐标为xi,需要送mi封信,然后邮局在0点,问你最少走多少路能送完信。
数据:
n是1e3,k,xi,mi都是1e7.
思路:
在纸上画一画,可以大概的发现,如果某次邮递员跨越了0点,那么和重新出发没有区别,哦不对,重新出发应该更优,能带更多的信。所以可以把问题拆分成两个独立的部分,解决正半轴以后,负半轴同理。
正半轴怎么办呢,明显是由远及近的送,然后递减就好了。
#include <bits/stdc++.h>using namespace std;typedef long long LL;typedef pair<int, int>pii;int n,k;const int maxn = 1e5 + 5;struct node{ LL id, x, m; bool operator < (const node &other)const { if(x != other.x) return x < other.x; if(m != other.m) return m < other.m; return id < other.id; }};LL x[maxn], m[maxn];LL solve(priority_queue<node>que){ LL ret = 0; while(que.size()) { node cur = que.top();que.pop(); LL temp = (cur.m + k - 1) / k;//send mail LL d = 0; if(cur.m % k != 0) d = k - cur.m % k; ret += temp * cur.x * 2LL;//走的距离 while(d) { if(que.size() == 0) break; node cur = que.top();que.pop(); int del = min(d, cur.m);//这个点能送掉的信,是两者的较小值 cur.m -= del; d -= del; if(cur.m != 0) que.push({cur}); } } return ret;}int main(){ scanf("%d%d", &n, &k); for(int i = 0; i < n; i++) scanf("%lld%lld", &x[i], &m[i]); priority_queue<node>que1, que2; for(int i = 0; i < n; i++) { if(x[i] > 0) que1.push({i, x[i], m[i]}); else que2.push({i, -x[i], m[i]}); } LL ans = 0; ans += solve(que1); ans += solve(que2); cout << ans << endl; return 0;}
K.Six Sides
题意:
有俩骰子,六个面的,然后告诉你他们各自面上分别是多少数值。一人扔一次,点数大的赢。如果相同,再扔一次,直到分出胜负。问你第一个人赢的概率。
数据:
思路:
。。推个公式就完。p是第一个人赢的概率,q是平局的概率,那么ans = sigma{p * q ^ k} 0 <= k。无穷等比数列。
#include <bits/stdc++.h>using namespace std;int main(){ int a[6], b[6]; for(int i = 0; i < 6; i++) { scanf("%d", &a[i]); } for(int i = 0; i < 6; i++) { scanf("%d", &b[i]); } int x = 0, y = 0; for(int i = 0; i < 6;i ++) { for(int j = 0; j < 6; j++) { if(a[i] > b[j]) x++; else if(a[i] == b[j]) y++; } } double p = x / 36.0, q = y / 36.0;//p为player1胜的概率 q为平局概率 printf("%.5f\n", p / (1.0 - q)); return 0;}
L.Three Square
emmm....不会做。但是,我有队友啊!2333M.Zigzag(dp)
题意:
问你形成一个上升下降交替进行的子串,最长是多少。
数据:
n不超过50。
思路:
不明白为什么数据这么水。。。n才50.
定义dp[i][k]:到第i个数字的时候,最后一步是递增的最长子串长度为dp[i][0],最后一步是递减的最长子串长度为dp[i][1]。
wa点:!!!相等情况!!!不能连啊- - 严格的递增递减
#include <bits/stdc++.h>using namespace std;int a[55];int dp[55][2];int main(){ int n; scanf("%d", &n); for(int i = 1; i <=n; i++) { scanf("%d", &a[i]); } dp[1][0] = dp[1][1] = 1; for(int i = 2; i <= n; i++) { for(int j = 0; j < i; j++) { if(a[i] > a[j]) dp[i][0] = max(dp[i][0], dp[j][1] + 1); else if(a[i] < a[j]) dp[i][1] = max(dp[i][1], dp[j][0] + 1); } } printf("%d\n", max(dp[n][0], dp[n][1])); return 0;}
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)【solved:12 / 13】
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 1) 【solved:9 / 12】
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest
- 2017/9/23周测(CF2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2))
- 2015-2016 ACM-ICPC Pacific Northwest Regional Contest Div.2 全部题目题解
- 2015-2016 ACM-ICPC Pacific Northwest Regional Contest Div.2( Problem V Gears)
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)C】【排序 模拟】Classy 课程难度排序超多关键字
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)D】【水题】Triangle 两个三角形是否可以恰好拼成矩形
- Codeforce Gym 100819P : 2015-2016 ACM-ICPC Pacific Northwest Regional Contest - P 仔细看题啊!
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)H】【迭代 排序 模拟】Hilbert Sort 图形拐拐划分,经过所有点的
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)E】【水题 贪心】Excellence n个数两两组合使得最小和尽可能大
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)A】【floyd 最小路径覆盖】最少飞机数满足所有航班要求
- 【2015-2016 ACM-ICPC Pacific Northwest Regional Contest (Div 1)G】【坐标轴变换 LIS】Racing Gems 开车吃宝石,横向速度不能超
- Codeforce Gym 100819L : 2015-2016 ACM-ICPC Pacific Northwest Regional Contest - L 这是一道阅读理解(微笑)
- [CF Gym 100827C] Containment [2014-2015 ACM-ICPC Pacific Northwest Regional Contest C]
- [CF Gym 100827E] Hill Number [2014-2015 ACM-ICPC Pacific Northwest Regional Contest E]
- [CF Gym 100827F] Knights [2014-2015 ACM-ICPC Pacific Northwest Regional Contest F]
- 身份证验证js
- ros, python初识
- Java 怎样修改文本文件内容
- MyBatis--关联关系查询--多对一--多表连接查询
- python常见数据处理方法
- 2016-2017 ACM-ICPC Pacific Northwest Regional Contest (Div. 2)【solved:12 / 13】
- PYTHON
- 大数据+互联网金融时代,“可以融资的BI”强势来袭!
- 数据结构-基数排序
- HDU-2354-Another Brick in the Wall
- hdu 1172 猜数字 (枚举)
- React 实用知识点
- 获取分组最新数据
- ACM-Billboard