在此记录,仅为方便复盘。
-第33场周赛
4207. 最长合法括号子序列
一个合法的括号序列满足以下条件:
序列()被认为是合法的。
如果序列X与Y是合法的,则XY也被认为是合法的。
如果序列X是合法的,则(X)也是合法的。
例如,(),()(),(())这些都是合法的。
现在,给定一个由 ( 和 ) 组成的字符串。
请你求出其中的最长合法括号子序列的长度。
注意,子序列不一定连续。
输入格式
共一行,一个由 ( 和 ) 组成的字符串。
输出格式
一个整数,表示最长合法括号子序列的长度。
数据范围
前五个测试点满足, 1≤输入字符串的长度≤10。
所有测试点满足,1≤输入字符串的长度≤106。
输入样例1:
(()))(
输出样例1:
4
输入样例2:
()()(()(((
输出样例2:
6
#include<iostream>
using namespace std;
int main(){
char x;
int flag=0,cnt=0,max=0;
while(cin>>x){
if(x=='('){
flag++;
cnt++;
}
if(x==')'&&flag>0){
flag--;
cnt++;
}
if(flag>=0)max=cnt-flag;
}
cout<<max;
return 0;
}
4208. 电话号码
一个电话销售员正在整理他的电话簿。
电话簿中记录了他的全部客户的电话号码。
一个客户可能有不止一个电话号码。
不同客户可能拥有完全相同的电话号码。
电话簿中一共包含 n 条记录。
每条记录都是首先包含一个字符串,表示客户的姓名,然后包含一个整数,表示本条记录包含的电话号码数量,最后是本条记录所包含的电话号码。
不同客户的姓名两两不同,所以如果两条记录包含的客户姓名相同,那么我们认为这都是记录的同一人的电话信息。
同一记录中可能包含相同的电话号码,不同记录中也可能包含相同的电话号码。
在进行整理时,应遵守如下原则:
如果一个客户拥有多条记录,则需要将这些记录进行合并,每人只保留一条记录,去记录他的全部有效号码。
如果一个客户记录的多个电话号码完全相同,则只保留一个作为有效号码,其余的全部视为无效号码。 如果一个客户记录的两个不同电话号码 a 和 b
满足 a 是 b 的后缀,则号码 a 视为无效号码。 请输出整理后的电话记录。
输入格式
第一行包含整数 n,表示记录数量。
接下来 n 行,每行描述一条记录,首先包含一个长度不超过 10 的由小写字母构成的非空字符串,表示客户姓名,然后包含一个不超过 10的正整数,表示本条记录包含的号码数量,最后包含本条记录的所有号码,每个号码都是长度不超过 10 的由数字构成的非空字符串,可能包含前导 0。
输出格式
首先输出一个整数 m,表示完成整理后的记录数量。
接下来 m 行,每行输出一条记录信息,格式要求与输入一致。
同一行的数据之间用单个空格隔开。
记录的先后顺序随意,一条记录中的号码顺序随意。
数据范围
前三个测试点满足 1≤n≤4。
所有测试点满足 1≤n≤20。
输入样例1:
2
i 1 00123
m 1 00123
输出样例1:
2
m 1 00123
i 1 00123
这道题没写,之后补上
-第34场周赛
4210. 数字
给定一个大于 2 的十进制正整数 A。
该数字在 2∼A−1 进制表示下的各位数字之和均可以求出。
例如,数字 123 在 16 进制表示下,共有 2 位:第 1 位是 7,第二位是 11,各位数字之和为 18。
现在,请你将 A 在 2∼A−1 进制表示下的各位数字之和全部相加,并将得到的结果除以 A−2,最终结果以最简分数形式输出。
输入格式
一个十进制正整数 A。
输出格式
输出格式为 X/Y,其中 X 表示输出答案的分子,Y 表示输出答案的分母。
数据范围
前三个测试点满足 3≤A≤10。
所有测试点满足 3≤A≤1000。
输入样例1:
5
输出样例1:
7/3
#include<iostream>
using namespace std;
int gcd(int a,int b){
return b?gcd(b,a%b):a;
}
int main(){
int a,i;
cin>>a;
int sum=0;
int b;
for(i=2;i<a;i++){
b=a;
while(b){
sum+=b%i; //短除法
b/=i;
}
}
int d=gcd(sum,a-2);
sum/=d;
a-=2;
a/=d;
cout<<sum<<"/"<<a;
return 0;
}
4211. 序列重排
给定一个长度为 n 的整数序列 a1,a2,…,an。
请你对序列进行重新排序(也可以保持原序列),要求新序列满足每个元素(第 1 个除外)都恰好是前一个元素的两倍或前一个元素的三分之一。
保证输入一定有解。
输入格式
第一行包含整数 n。
第二行包含 n 个整数 a1,a2,…,an。
输出格式
一行 n 个整数,表示排序后的序列。输出任意合法方案即可。
数据范围
前三个测试点满足 2≤n≤10。
所有测试点满足 2≤n≤100,1≤ai≤3×1018。
输入样例1:
6
4 8 6 3 12 9
输出样例1:
9 3 6 12 4 8
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
int get(ll x,ll b){
int res=0;
while(x%b==0){
res++;
x/=b;
}
return res;
}
int main(){
int n;
cin>>n;
vector<ll> t[n];
int i;
for(i=0;i<n;i++){
ll x;
cin>>x;
t[i]={get(x,2),-get(x,3),x};
}
sort(t,t+n);
for(i=0;i<n;i++){
cout<<t[i][2]<<" ";
}
return 0;
}
-第35场周赛
4213. 最小结果
有四个整数 a,b,c,d。
有三个操作符 op1,op2,op3,每个操作符要么是 *(表示乘法),要么是 +(表示加法)。
现在,我们要进行如下操作:
从现有整数中选出两个,按 op1 进行运算,得到结果。将选出的两个整数舍弃,并将结果保留。此时我们还剩下三个整数。
从现有整数中选出两个,按op2 进行运算,得到结果。将选出的两个整数舍弃,并将结果保留。此时我们还剩下两个整数。
从现有整数中选出两个,按 op3进行运算,得到结果。将选出的两个整数舍弃,并将结果保留。此时我们只剩下一个整数。
我们希望,最后剩下的一个整数尽可能小。
输入格式
第一行包含四个整数 a,b,c,d。
第二行包含三个操作符 op1,op2,op3,每个操作符要么是 *,要么是 +。
输出格式
输出最后剩下的一个整数的最小可能值。
数据范围
所有测试点满足 0≤a,b,c,d≤1000。
输入样例1:
1 1 1 1
+ + *
输出样例1:
3
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
char op[5];
LL ans=1e18;
void dfs(vector<LL> v,int u){
if(v.size()==1)ans=min(ans,v[0]);
else{
for(int i=0;i<v.size();i++){
for(int j=i+1;j<v.size();j++){
vector<LL> t;
for(int k=0;k<v.size();k++){
if(k!=i&&k!=j){
t.push_back(v[k]);
}
}
if(op[u]=='*')t.push_back(v[i]*v[j]);
else t.push_back(v[i]+v[j]);
dfs(t,u+1);
}
}
}
}
int main(){
vector<LL> v(4);
int i,j;
for(i=0;i<4;i++)cin>>v[i];
for(i=0;i<3;i++)cin>>op[i];
dfs(v,0);
cout<<ans<<endl;
return 0;
}
4214. 三元组
给定两个长度为 n 的整数序列 s1,s2,…,sn 和 c1,c2,…,cn。
请你找到一个三元组 (i,j,k),满足以下所有条件:
i<j<k si<sj<sk ci+cj+ck 尽可能小 输出 ci+cj+ck 的最小可能值。
输入格式 第一行包含整数 n。
第二行包含 n 个整数 s1,s2,…,sn。
第三行包含 n 个整数 c1,c2,…,cn。
输出格式
如果满足条件的三元组不存在,则输出 −1。
否则,输出 ci+cj+ck 的最小可能值。
数据范围
前 5 个测试点满足 3≤n≤10。
所有测试点满足 3≤n≤3000,1≤si≤109,1≤ci≤108。
输入样例1:
5
2 4 5 4 10
40 30 20 10 40
输出样例1:
90
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int s[3001],c[3001];
const int INF=5e8;
int main(){
int n;
cin>>n;
int i;
int res=INF;
for(i=0;i<n;i++)cin>>s[i];
for(i=0;i<n;i++)cin>>c[i];
for(int j=0;j<n;j++){
int left=INF;
for(i=0;i<j;i++){
if(s[i]<s[j])left=min(left,c[i]);
}
int right=INF;
for(int k=j+1;k<n;k++){
if(s[k]>s[j])right=min(right,c[k]);
}
res=min(res,left+c[j]+right);
}
if(res==INF)res=-1;
cout<<res<<endl;
return 0;
}
-第36场周赛
没有,之后补上
-第37场周赛
4297. 截断数组
给定一个长度为 n 的数组 d1,d2,…,dn。
现在,要将该数组从中间截断,得到三个子数组(可以为空)。
不妨设第一个子数组包含 a 个元素,第二个子数组包含 b 个元素,第三个子数组包含 c 个元素。
那么三个子数组的各元素之和 sum1,sum2,sum3 依次为:
sum1=∑1≤i≤adi,sum2=∑a+1≤i≤a+bdi,sum3=∑a+b+1≤i≤a+b+cdi。
注意,空数组的各元素之和为 0。
我们希望截断后的三个子数组满足:
sum1=sum3。 满足上一条件的情况下,sum1 尽可能大。 请你计算并输出 sum1 的最大可能值。
显然,本题一定有解,因为可以令 a=0,b=n,c=0。
输入格式
第一行包含整数 n。
第二行包含 n 个整数 d1,d2,…,dn。
输出格式
输出一个整数,表示 sum1 的最大可能值。
数据范围
前 6 个测试点满足 1≤n≤10。
所有测试点满足 1≤n≤2×105,1≤di≤109。
输入样例1:
5
1 3 1 1 4
输出样例1:
5
#include<iostream>
using namespace std;
int main(){
int n;
cin>>n;
int a[n];
int i;
for(i=0;i<n;i++){
cin>>a[i];
}
long long sum1=0,sum2=0,sum=0;
for(i=0;i<=n;){
if(sum1==sum2){
sum=sum1;
sum1+=a[i];
sum2+=a[n-1];
i++;
n--;
}else if(sum1>sum2){
sum2+=a[n-1];
n--;
}else if(sum1<sum2){
sum1+=a[i];
i++;
}
}
cout<<sum;
return 0;
}
4298. 搭档
有 n 个男孩,每个人的魅力值依次为 a1,a2,…,an.
有 m 个女孩,每个人的魅力值依次为 b1,b2,…,bm。
学校举办舞会,希望选出尽可能多的男女搭档参加。
已知,当一对男女的魅力值相差不超过 1 时,他们才会愿意组成搭档。
请问,最多可以同时凑出多少对搭档参加舞会。
注意:
不能男男配对或女女配对。 每个男生最多只能和一个女生配对,反之亦然。 输入格式 第一行包含整数 n。
第二行包含 n 个整数 a1,a2,…,an。
第三行包含整数 m。
第四行包含 m 个整数 b1,b2,…,bm。
输出格式
一个整数,表示最大可能对数。
数据范围
前 6 个测试点满足 1≤n,m≤5,
所有测试点满足 1≤n,m≤100,1≤ai,bi≤100。
输入样例1:
4
1 4 6 2
5
5 1 5 7 9
输出样例1:
3
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
int main(){
int n,m,i,j;
cin>>n;
int a[n];
for(i=0;i<n;i++){
cin>>a[i];
}
cin>>m;
int b[m];
for(i=0;i<m;i++){
cin>>b[i];
}
sort(a,a+n);
sort(b,b+m);
int ans=0;
for(i=0,j=0;i<n;){
if(j==m)break;
if(abs(a[i]-b[j])<=1){
ans++;
i++;
j++;
}else if(a[i]>b[j])j++;
else if(a[i]<b[j])i++;
}
cout<<ans;
return 0;
}