2019暑训第一场训练赛 |(2016-icpc区域赛)部分题解
// 今天下午比赛自闭了,晚上补了题,把AC的部分水题整理一下,记录坑点并吸取教训。
// CF补题链接:http://codeforces.com/gym/101291
A - Alphabet
题目大意:
给定一字符串,问至少需要添加多少字母后,能使该字符串删掉一些字母后成为“abcdefghijklmnopqrstuvwxyz"的序列。
分析及代码:
最长上升子序列(LIS)问题,n的规模不大,直接DP两重循环求解。答案为 26-最长上升子序列的长度。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; int main() {
char str[];
int dp[]; // dp[i] 以str[i]结尾的最长上升子序列的长度
// dp[i] = max(dp[i], dp[k]+1), 0<=k<i, str[k]<str[i]
int maxLen = ; // maxLen = max(dp[i]), 0<=i<n
scanf("%s", str);
int len = strlen(str);
for(int i=;i<len;i++) {
dp[i] = ;
for(int j=;j<i;j++) {
if(str[j]<str[i]) {
dp[i] = max(dp[i], dp[j]+);
}
}
maxLen = max(maxLen, dp[i]);
} printf("%d\n", -maxLen); return ;
}
顺便学习了求解最长公共子序列(LCS)与LIS的O(nlogn)算法,其利用了贪心思想和二分搜索。
数组dp表示目前找到的最长序列,不影响dp长度前提下,在原序列中尽可能找到更小的元素来代替现有的最长序列中的元素;如果比最大的元素要大,就添加在dp末尾。
由于数组dp单调,使用二分搜索能将更新的复杂度降低到O(logn),所以总的复杂度为O(nlogn)。
// 返回最长上升子序列的长度
// 时间复杂度: O(nlogn)
// 来源:https://blog.csdn.net/ltrbless/article/details/81318935
//
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
char arr[], dp[];
scanf("%s", arr);
int n = strlen(arr); /* 求解最长子序列的个数的核心代码 */
/* ********************************************** */
int k = ;
dp[k] = arr[];
for(int i=;i<n;i++) {
if(dp[k]<arr[i]) dp[++k] = arr[i]; //如果比最后一个元素大,那么就添加再最后末尾处
else *(lower_bound(dp, dp+k, arr[i])) = arr[i]; //如果比最后一个元素小,那么就替换该序列第一个比他大的数;
}
/* ********************************************** */ printf("最长子序列的个数为: %d\n", k);
return ; }
B - Barbells
题目大意:
分别给你n个杠铃的重量和m个盘子的重量,可以把盘子加到杠铃上,但要两边的重量相同。输出全部能组合的杠铃重量。
分析及代码:
n,m不超过14,直接枚举全部可能,也没什么技巧了。
比赛时候写这题,电脑突然崩溃了,代码都不见了,心态爆炸。。。
直接用DFS算重量的组合,把m当做n作为终止条件,debug没看出来。改用储存全部组合的状态(二进制),懒得去重排序都一股脑往set里放,写了自己都看不懂的代码交上去就过了。
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<set>
using namespace std; int n, m;
map<int, int> sums;
vector<int> vec[];
int sum[];
int cnt;
int arr2[], arr[];
set<int> ans;
set<int> ans2;
int main()
{
cin>>n>>m;
for(int i=;i<n;i++) {
scanf("%d", &arr[i]);
}
for(int i=;i<m;i++) {
scanf("%d", &arr2[i]);
} for(int s=;s<(<<m)-;s++) {
int now = ;
for(int k=;k<m;k++) {
if((s>>k)&) {
now += arr2[k];
}
}
if(sums.find(now)==sums.end()) {
sums[now] = ++cnt;
sum[cnt] = now;
vec[sums[now]].push_back(s);
}else
vec[sums[now]].push_back(s);
} ans.insert();
for(int i=;i<=cnt;i++) {
if(vec[i].size()>) {
// cout<<sum[i]<<':';
for(int j=;j<vec[i].size();j++) {
for(int k=j+;k<vec[i].size();k++) {
if((vec[i][j] & vec[i][k])==) {
ans.insert(*sum[i]);
}
}
}
}
}
for(set<int>::iterator it=ans.begin();it!=ans.end();it++) {
for(int i=;i<n;i++) {
ans2.insert(*it+arr[i]);
}
}
for(set<int>::iterator it=ans2.begin();it!=ans2.end();it++)
{
printf("%d\n", *it);
}
return ;
}
晚上重新用DFS还带剪枝的,重新写了一遍。
dfs(k, left, right),每层三个分支,不用set<int>而用数组储存中间组合结果,一定要开辟足够的内存空间(3^14),否则就奇怪地WA了(为什么不是运行错误???)。
最后也没有用set去排序,复习一下unique函数的用法。
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<set>
using namespace std; int n, m;
int a[], b[], bSum;
//int bbb[20010]; // 单边有2^14种组合,约16000, 会WA
//int bbb[5000000]; // 3^14, AC
set<int> bbb; int ans[]; // 14*16000
int k; void dfs(int k, int left, int right) {
if(k==m+) {
if(left==right) {
bbb.insert(left*);
}
return;
}
if(left>bSum/ || right>bSum/) return; dfs(k+, left+b[k], right);
dfs(k+, left, right+b[k]);
dfs(k+, left, right);
}
int main()
{
cin>>n>>m;
for(int i=;i<=n;i++) {
scanf("%d", &a[i]);
}
for(int i=;i<=m;i++) {
scanf("%d", &b[i]);
bSum += b[i];
} dfs(, , ); for(int i=;i<=n;i++) {
for(set<int>::iterator it=bbb.begin();it!=bbb.end();it++) {
ans[++k] = a[i] + *it;
}
} sort(ans+, ans++k);
k = unique(ans+, ans++k) - (ans+); for(int i=;i<=k;i++) {
printf("%d\n", ans[i]);
} return ;
}
F - Equality
题目大意:
签到题。
分析及代码:
没有代码。
G - Gravity
题目大意:
似乎是模拟苹果下落?输出最后苹果的状态。
分析及代码:
没想到苹果可能在障碍的下方(题目也没有说明,被样例误导以为苹果都在天上),WA了几次自闭了。
苹果的下落就相当于在垂直方向上苹果‘o'与空气’.'进行排序。
要避免障碍就使用相邻交换排序,相邻只要有苹果在空气上方就互换位置。 冒泡排序的思想?
#include<iostream>
#include<cstdio>
using namespace std; char mp[][];
int n, m;
int h[], num[];
int main() {
cin>>n>>m;
getchar();
for(int i=;i<n;i++) {
scanf("%s", mp[i]);
} for(int j=;j<m;j++) {
for(int i=;i<n;i++) {
for(int k=;k<n;k++) {
if(mp[k-][j]=='o' && mp[k][j]=='.') {
mp[k-][j] = '.';
mp[k][j] = 'o';
}
}
} } for(int i=;i<n;i++) puts(mp[i]);
return ;
}
H - Islands
题目大意:
给你一块卫星地图,L表示陆地,W表示水域,C表示有云挡住。问最少可能有多少块岛。
分析及代码:
本以为还要建图,求联通分量啥的。。。
L与C连起来不影响岛的个数,直接从每块L区域DFS求联通块个数即可。
#include<cstdio>
#include<iostream>
#include<vector>
#include<map>
#include<queue>
#include<set>
using namespace std; int n, m;
const int dx[] = {, , , -};
const int dy[] = {, -, , };
char mp[][];
bool vis[][];
void dfs(int x, int y) {
vis[x][y] = ;
for(int i=;i<;i++) {
int nx = x + dx[i];
int ny = y + dy[i]; if(nx>= && nx<n && ny>= && ny<m && !vis[nx][ny] && mp[nx][ny]!='W') {
dfs(nx, ny);
}
}
} int main()
{
cin>>n>>m;
getchar();
for(int i=;i<n;i++) {
scanf("%s", mp[i]);
} int ans = ;
for(int i=;i<n;i++) {
for(int j=;j<m;j++) {
if(!vis[i][j] && mp[i][j]=='L') {
dfs(i, j);
ans++;
}
}
} printf("%d\n", ans);
return ;
}
J - Postman
题目大意:
邮递员在原点,要给分布在x轴上的n个客户送信,每个客户有mi封信件,每次配送最多带k封信。求送完信最少需要多长时间。
分析及代码:
贪心吧。由于走到最远再回到原点会经过更近的点,每次带k封信,送完最远的顺路给次远的,这样优先配送距离最远的信件,送完最远的再送第二远的,依次下去。
注意x正负区间分别计算。
#include<cstdio>
#include<iostream>
#include<algorithm> using namespace std; typedef long long ll;
int n, k;
struct node {
int x, m;
bool operator<(const node &a)const {
return x<a.x;
}
}n1[], n2[];
int cnt1, cnt2; int main()
{
cin>>n>>k;
for(int i=;i<n;i++) {
int x, m;
scanf("%d %d", &x, &m);
if(x<) {
n1[++cnt1].x = -x;
n1[cnt1].m = m;
} else {
n2[++cnt2].x = x;
n2[cnt2].m = m;
}
}
sort(n1+, n1++cnt1);
sort(n2+, n2++cnt2); ll ans = ;
for(int i=cnt1;i>=;i--) {
if(n1[i].m>) {
int t = (n1[i].m+k-) / k;
ans += *(ll)n1[i].x* t;
int left = t*k - n1[i].m; int j = i-;
while(j>=) {
if(n1[j].m>=left) {
n1[j].m -= left;
break;
}
else {
left -= n1[j].m;
n1[j].m = ;
j--;
}
}
}
} for(int i=cnt2;i>=;i--) {
if(n2[i].m>) {
int t = (n2[i].m+k-) / k;
ans += *(ll)n2[i].x* t;
int left = t*k - n2[i].m; int j = i-;
while(j>=) {
if(n2[j].m>=left) {
n2[j].m -= left;
break;
}
else {
left -= n2[j].m;
n2[j].m = ;
j--;
}
}
}
} printf("%lld\n", ans);
return ;
}
K - Six Sides
题目大意:
弱智概率题。。。(卡了半天怪我英语太差没读懂咯O.O)
分析及代码:
结果为: 赢局数 / (36 - 平局数)
为什么呢?反正我WA了两次队友告诉我的。
设单次胜的概率为p=win/36,平局概率为q=pin/36
总体赢的概率P为 p + q*p + q*q*p + q*q*q*p + ... = p/(1-q)
所以 P = win / (36 - pin)
#include<iostream>
#include<cstdio>
using namespace std; int mp[][];
int a[], b[];
int main() {
for(int i=;i<;i++) cin>>a[i];
for(int i=;i<;i++) cin>>b[i]; int win=, p=, lose= ;
for(int i=;i<;i++) {
for(int j=;j<;j++) {
if(a[i]>b[j]) win++;
else if(a[i]==b[j]) p++;
else lose++;
}
}
if(win==lose) printf("%.5lf\n", 0.5);
else printf("%.5lf\n", (win+0.0)/(-p));
return ;
}
(未完待续。。。)
2019暑训第一场训练赛 |(2016-icpc区域赛)部分题解的更多相关文章
- ACM-ICPC 2016亚洲区域赛(沈阳站)游记(滚粗记)
首发于QQ空间和知乎,我在这里也更一下. 前言 以前高中搞竞赛的时候,经常看到神犇出去比赛或者训练之后写游记什么的,感觉萌萌哒.但是由于太弱,就没什么心情好写.现在虽然还是很弱,但是抱着享受的心情 ...
- UVALive 7146 (贪心+少许数据结构基础)2014acm/icpc区域赛上海站
这是2014年上海区域赛的一道水题.请原谅我现在才发出来,因为我是在太懒了.当然,主要原因是我刚刚做出来. 其实去年我就已经看到这道题了,因为我参加的就是那一场.但是当时我们爆零,伤心的我就再也没有看 ...
- 【2019多校第一场补题 / HDU6578】2019多校第一场A题1001Blank——dp
HDU6578链接 题意 有一串字符串,仅由 {0,1,2,3}\{0, 1, 2, 3\}{0,1,2,3} 组成,长度为 nnn,同时满足 mmm 个条件.每个条件由三个整数组成:l.r.xl.r ...
- Gym.102059: 2018-2019 XIX Open Cup, Grand Prix of Korea(寒假gym自训第一场)
整体来说,这一场的质量比较高,但是题意也有些难懂. E.Electronic Circuit 题意: 给你N个点,M根线,问它是否是一个合法的电路. 思路: 一个合法的电路,经过一些串联并联关系, ...
- 杭电2019多校第一场,Problem I,String 2019
题目描述 Tom has a string containing only lowercase letters. He wants to choose a subsequence of the str ...
- 【2019多校第一场补题 / HDU6582】2019多校第一场E题1005Path——最短路径+网络流
HDU6582链接 题意 在一张有向图中,有一个起点和一个终点,你需要删去部分路径,使得起点到终点的最短距离增加(并不要求需要使得距离变成最大值),且删除的路径长度最短.求删去的路径总长为多少 分析 ...
- 2016青岛区域赛.Coding Contest(费用流 + 概率计算转换为加法计算)
Coding Contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)To ...
- 2016 ACM-ICPC 区域赛(大连站)题解
题目链接 A - Wrestling Match (二分图染色) 题意略坑(没有说好的玩家一定能打过差的玩家啊啊~~) 典型的二分图染色问题,每个玩家看成一个点,把相互较量过的玩家之间连边,好的玩家染 ...
- 2019年icpc区域赛银川站总结
目录 一.前言 二.10月19日热身赛 三.10月20日正式赛 四.结果 一.前言 比赛前我们队有ccpc厦门和icpc银川的名额,然而这两个地区的时间正好撞了,考虑到银川更容易拿奖,加上我们ACM协 ...
随机推荐
- JS事件 卸载事件 当用户退出页面时(页面关闭、页面刷新等),触发onUnload事件,同时执行被调用的程序。注意:不同浏览器对onunload事件支持不同。
卸载事件(onunload) 当用户退出页面时(页面关闭.页面刷新等),触发onUnload事件,同时执行被调用的程序. 注意:不同浏览器对onunload事件支持不同. 如下代码,当退出页面时,弹出 ...
- 2000w数据,redis中只存20w的数据,如何保证redis中的数据都是热点数据
redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略.redis 提供 6种数据淘汰策略: voltile-lru:从已设置过期时间的数据集(server.db[i].expires) ...
- vue better-scroll 下拉上拉,加载刷新
_initScroll(){ this.$nextTick(() => { if (!this.scroll) { ...
- 安装xampp之后报错XAMPP: Starting Apache...fail.
1.安装完成xampp之后报错: 2.网上查到的解决办法是:输入sudo apachectl stop 之后再次启动lampp,问题得以解决: 过两天发现问题并没有解决: ①在网上查询发现是因为端口被 ...
- python3正则表达式指南
1.正则表达式基础 1.1 简单介绍 正则表达式并不是Python的一部分.正则表达式是用于处理字符串的强大工具,拥有自己独特的语法以及一个独立的处理引擎,效率上可能不如str自带的方法,但功能十分强 ...
- [TJOI 2018]游园会
题意:求NOI的合法串... 思路: 首先这个似乎和后缀自动机没关系(话说TJ不考后缀自动机??),其实就是一个\(DP\)套\(DP\),考虑如果不看兑奖串就是一个LCS,当出现时多记一维即可. # ...
- 牛客多校第四场 A meeting 树的半径
题意: 有一棵树,树上有许多人,他们要聚会,找一个点使得所有人到这个点的距离的最大值最小. 题解: 首先,以一个有人的点为根,求一个生成树,删掉所有没有人的子树,保证所有的悬挂点(只连接一条边的点)都 ...
- (3)mysql表和字段的操作
创建表 create table name( id int, student ) ); 查看表结构 ****常用**** describe 表名; 修改表名 老表 rename 新表 ALTER TA ...
- 深入分析Service启动、绑定过程
Service是Android中一个重要的组件,它没有用户界面,可以运行在后太做一些耗时操作.Service可以被其他组件启动,甚至当用户切换到其他应用时,它仍然可以在后台保存运行.Service 是 ...
- SpringAOP中的aop:config标签
我们使用Spring的AOP功能的时候发现,我们使用普通的配置方式的时候,我们无法精确的确定将切面类中的哪个方法切入到哪个切入点上, 所以我们可以使用aop的专用标签来完成相关的配置.其中主要表现是使 ...