hihocoder编程练习赛55

hihocoder编程练习赛55

A

描述

给定:
1)N个正整数A1, A2, … AN;
2)P个加号+和Q个减号-; (P+Q=N-1)
3)K对括号()
请你使用全部整数、加减号和括号,组成一个合法的算式(A1~AN在算式中的顺序随意),使得算式的结果最大。
注意加减号只能作为二元运算符出现在算式中,不能作为正负号。
括号可以出现在算式最左和最右,例如(((1+2)))是合法的。
例如对于样例数据,(2-1)+3或3+(2-1)等都是结果最大的算式。

输入
第一行包含4个整数,N,P, Q和K。
第二行包含N个整数A1, A2, … AN。
2 ≤ N ≤ 100 P+Q+1=N 0 ≤ K ≤ 10
1 ≤ Ai ≤ 1000

输出
最大算式结果

样例输入
3 1 1 1
1 2 3

样例输出
4

参考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
#include<bits/stdc++.h>
#define maxn 150
using namespace std;
int n,p,q,k;
int a[maxn];
bool cmp(int x,int y){
return x>y;
}
int main(){
// freopen("input.txt","r",stdin);
cin>>n>>p>>q>>k;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+1+n,cmp);
int ans=0;
if(k==0){
for(int i=1;i<=n;i++){
if(i<=p+1) ans+=a[i];
else ans-=a[i];
}
}
else{
for(int i=1;i<n;i++) ans+=a[i];
ans-=a[n];
}
cout<<ans<<endl;
return 0;
}

思路

贪心
排序 若没有括号 从大开始先补加号后补减号
若有括号 根据-(最小-最大-次大-···) 只需要一个括号就可以把除最小外 其余均变成正数 所以答案就是前n-1大减去最小值

B

描述
我们称两个长度相等的字符串A和B是朋友字符串,当且仅当
1)A和B只有两个位置i和j的对应字符不同,即A[i] ≠ B[i]且A[j] ≠ B[j]
2)一个字符串如果交换位于i和j的字符将变成另一个字符串。
例如conserve和converse就是朋友字符串。
现在给定N个长度相同的字符串S1, S2, … SN,请你求出其中有多少对朋友字符串。

输入
第一行包含一个整数N。
以下N行每行一个只包含小写字母的字符串Si。
对于70%的数据,1 ≤ N ≤ 1000,
对于100%的数据,1 ≤ N ≤ 20000, |Si| ≤ 10

输出
一个整数代表答案

样例输入
4
aaba
aaab
abaa
baaa

样例输出
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
#include<bits/stdc++.h>
#define maxn 50
using namespace std;
int n;
map<string,int>mp;
char s[maxn];
int main(){
// freopen("input.txt","r",stdin);
scanf("%d",&n);
int ans=0;
for(int i=1;i<=n;i++){
scanf("%s",s);
int len=strlen(s);
for(int i=0;i<len;i++){
for(int j=i+1;j<len;j++){
if(s[i]!=s[j]){
swap(s[i],s[j]);
if(mp.count(s)) ans+=mp[s];
swap(s[i],s[j]);
}
}
}
mp[s]++;
}
cout<<ans<<endl;
return 0;
}

思路

注意len<=10 所以直接暴力 map存储每个字符串出现的次数
对于每个字符串暴力交换2个不同的位置 判断交换后的字符串是否出现 若出现 加上出现的次数

C

描述
给定N个闭区间[A1, B1], [A2, B2], [A3, B3] … [AN, BN],请你计算没有被这些区间覆盖的第K小的正整数是多少?

输入
第一行包含两个整数N和Q,分别代表区间数目和询问数目。
以下N行每行包含两个整数Ai和Bi。
最后一行包含Q个整数,K1, K2, … KQ,代表Q次询问。
对于50%的数据,1 ≤ N, Q ≤ 1000
对于100%的数据,1 ≤ N, Q ≤ 100000 0 ≤ Ai ≤ Bi ≤ 1000000000 1 ≤ Ki ≤ 1000000000

输出
对于每次询问Ki,输出没有被这些区间覆盖的第Ki小的正整数是多少。
每个答案一行。

样例输入
3 3
10 20
15 22
30 40
5
10
15

样例输出
5
23
28

参考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
#include<bits/stdc++.h>
#define mp make_pair
#define maxn 100050
using namespace std;
int n,q;
vector<pair<int,int> >v1,v2;
int pre_len[maxn];
int main(){
// freopen("input.txt","r",stdin);
cin>>n>>q;
for(int i=1;i<=n;i++){
int x,y;
cin>>x>>y;
v1.push_back(mp(x,y));
}
sort(v1.begin(),v1.end());
if(v1[0].first>1) v2.push_back(mp(1,v1[0].first-1));
int ed=v1[0].second;
for(int i=1;i<v1.size();i++){
if(v1[i].first>ed+1){
v2.push_back(mp(ed+1,v1[i].first-1));
ed=v1[i].second;
}
else ed=max(ed,v1[i].second);
}
v2.push_back(mp(ed+1,2000000000));
pre_len[0]=v2[0].second-v2[0].first+1;
for(int i=1;i<v2.size();i++){
pre_len[i]+=pre_len[i-1]+v2[i].second-v2[i].first+1;
}
// for(int i=0;i<v2.size();i++) cout<<pre_len[i]<<endl;
while(q--){
int k;
cin>>k;
int l=0,r=v2.size();
int ans=0;
while(l<=r){
int mid=l+r>>1;
if(pre_len[mid]>=k) r=mid-1,ans=mid;
else l=mid+1;
}
if(ans>0) k-=pre_len[ans-1];
cout<<v2[ans].first+k-1<<endl;
}
return 0;
}

思路

所有区间按照左端点排序 v2记录所有未被覆盖的区间 用pre_len求出这些区间元素个数的前缀和
二分k所在的区间位置 找到大于等于k的第一个位置
两个wa点:
1.二分找到的ans要减去pre_len[ans-1]才是在第ans个区间所在的位置 但如果ans为0 无需减
2.v2 push的区间右限 由于ai小于1e9 k小于1e9 所以区间的右限最多为2e9

文章目录
  1. 1. hihocoder编程练习赛55
    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. 思路
|