hihocoder编程练习赛56

hihocoder编程练习赛56

A

描述

小Hi的面前摆放了N张卡片,每张卡片都有A和B两面。其中第i张卡片的A面写着一个整数Ai,B面写着一个整数Bi。
一开始所有卡片都是A面向上。现在小Hi必须选择一张卡片,将其翻成B面向上。
设N张卡片向上那一面的数字组成的集合是S,那么游戏的得分是:最小的不属于S的正整数。
例如S={1, 2, 4, 6, 7},则得分是3。
你能算出小Hi最多能得多少分么?

输入
第一行包含一个整数N。
第二行包含N个整数Ai。
第三行包含N个整数Bi。
对于50%的数据,1 ≤ N ≤ 1000
对于100%的数据,1 ≤ N ≤ 100000 1 ≤ Ai, Bi ≤ 1000000

输出
输出最大得分

样例输入
5
1 2 3 5 6
3 4 3 4 4

样例输出
6

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include<bits/stdc++.h>
#define maxn 100050
using namespace std;
int n;
int a[maxn],b[maxn];
int num[maxn*10];
set<int>s;
int main(){
// freopen("input.txt","r",stdin);
scanf("%d",&n);
memset(num,0,sizeof num);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),num[a[i]]++;
for(int i=1;i<=n;i++) scanf("%d",&b[i]);
for(int i=1;i<=1000000;i++){
if(!num[i]) s.insert(i);
}
int ans=0;
for(int i=1;i<=n;i++){
num[a[i]]--;
num[b[i]]++;
s.erase(b[i]);
if(num[a[i]]==0) s.insert(a[i]);
ans=max(ans,*s.begin());
num[a[i]]++;
num[b[i]]--;
s.erase(a[i]);
if(num[b[i]]==0) s.insert(b[i]);
}
cout<<ans<<endl;
return 0;
}

思路

本题相当于要维护一个未出现数字集合的小根堆 并且要满足插入删除操作 联想到set
然后暴力模拟即可

B

描述
小Hi得到了一张藏宝图。图中有一串数字字符串,小Hi分析应该是一处坐标”X,Y”,例如”13.2,20”。
可以由于藏宝图年代久远,标点符号’.’和’,’都消失不见了,只剩下一串数字,例如”13220”。
你能帮助小Hi从数字串还原出所有可能的坐标吗?
合法的X或Y应满足:

  1. 是一个整数或小数。
  2. 没有多余的0。例如”03”,”0.10”, “00.2”, “1.0”都不合法。
  3. 小数点不能在首尾。例如”.2”, “2.”都不合法。

输入
一个数字字符串,长度不超过6。
输入保证有解。

输出
所有可能的坐标,每个一行。
按X从小到大输出;如果X相同,按Y从小到大输出。

样例输入
13220

样例输出
1,3220
1.3,220
1.32,20
1.322,0
13,220
13.2,20
13.22,0
132,20
132.2,0
1322,0

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#include<bits/stdc++.h>
using namespace std;
string s;
vector<pair<double,double> >a;
bool check(string s){
int len=s.length();
int flag=0;
for(int i=0;i<len;i++){
if(s[i]=='.'){
flag=1;
break;
}
}
if(len==1) return true;
if(s[0]=='0' && s[1]!='.') return false;
if(flag && s[len-1]=='0') return false;
if(!flag) return true;
return true;
}
void fun(string s1,string s2){
int len1=s1.length();
int len2=s2.length();
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(i!=len1) s1.insert(i,".");
if(j!=len2) s2.insert(j,".");
// cout<<s1<<" "<<s2<<" "<<check(s1)<<" "<<check(s2)<<endl;
if(check(s1) && check(s2)){
double x,y;
if(len1==0 && s1[0]=='0') x=0;
else x=atof(s1.c_str());
if(len2==0 && s2[0]=='0') y=0;
else y=atof(s2.c_str());
a.push_back(make_pair(x,y));
}
if(i!=len1) s1.erase(i,1);
if(j!=len2) s2.erase(j,1);
}
}
}
int main(){
// freopen("input.txt","r",stdin);
cin>>s;
int len=s.length();
for(int i=1;i<len;i++){
string s1=" ",s2=" ";
s1=s.substr(0,i);
s2=s.substr(i,len-i);
fun(s1,s2);
}
sort(a.begin(),a.end());
for(int i=0;i<a.size();i++){
cout<<a[i].first<<","<<a[i].second<<endl;
}
return 0;
}

思路

暴力拆分 每个部分再暴力小数点位置 check后加入pair排序输出
atof实现string转duuble check函数注意先后顺序

C

描述
有N件物品,分别属于很多不同的类别。现在你陆续知道若干对物品的关系,用字母R接一个三元组表示:
R X Y 1,表示X和Y属于同一个类别;
R X Y 2,表示X和Y属于不同的类别;
同时,你也会被询问某对物品的关系,用字母Q接一个二元组表示:
Q X Y,表示询问X和Y的关系。
你需要根据已知的关系推断,如果X和Y属于同一个类别,输出1;如果X和Y属于不同的类别,输出2;如果不确定,输出3。

输入
第一行包含两个整数N和M,N是物种总数,M是以下R和Q指令的总和。
以下N行,每行包含一条指令。
对于50%的数据,1 ≤ N ≤ 1000, 1 ≤ M ≤ 2000
对于100%的数据,1 ≤= N ≤ 100000 1 ≤ M ≤ 200000 1 ≤ X, Y ≤ N
数据保证没有矛盾

输出
对于每一条Q指令,输出1/2/3代表两个物品的关系。

样例输入
6 9
R 1 2 1
R 1 3 1
R 1 4 2
Q 2 4
Q 1 6
R 3 6 1
R 4 5 2
Q 1 5
Q 1

样例输出
2
3
3
1

参考AC代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<bits/stdc++.h>
#define maxn 100050
using namespace std;
int n,m;
int p[maxn];
set<int>s[maxn];
int find(int x){
return x==p[x]?x:p[x]=find(p[x]);
}
void merge(int a,int b){
int x=find(a);
int y=find(b);
if(x!=y){
// if(s[x].size()<s[y].size()) swap(x,y);
for(auto pp:s[y]) s[x].insert(find(pp));
p[y]=x;
}
}
int main(){
// freopen("input.txt","r",stdin);
cin>>n>>m;
for(int i=0;i<=n;i++) p[i]=i;
while(m--){
char op;
cin>>op;
if(op=='R'){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z==1) merge(x,y);
else{
x=find(x),y=find(y);
s[x].insert(y),s[y].insert(x);
}
}
else if(op=='Q'){
int x,y;
scanf("%d%d",&x,&y);
x=find(x),y=find(y);
int ans=0;
if(x==y) ans=1;
else if(s[x].count(y) || s[y].count(x)) ans=2;
else ans=3;
cout<<ans<<endl;
}
}
return 0;
}

思路

并查集相关 基础上再加一个二维set判断不是集合的元素
如果x和y在一个集合里 那么x和所有不和y是一个集合的元素也不在一个集合中 反之同理 处理好merge函数即可 用set模拟
本题启发式合并没有加速很多

文章目录
  1. 1. hihocoder编程练习赛56
    1. 1.1. A
      1. 1.1.1. 参考AC代码
      2. 1.1.2. 思路
    2. 1.2. B
      1. 1.2.1. 参考AC代码
      2. 1.2.2. 思路
    3. 1.3. C
      1. 1.3.1. 参考AC代码
      2. 1.3.2. 思路
|