第35场周赛
P4212. 字符串比较
先全部变为小写(-32),再依次比较
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int main(){
string a,b;
cin>>a>>b;
for(int i=0;i<a.length();i++){
int x=a[i]-'0';
int y=b[i]-'0';
if(x>=49) x-=32;
if(y>=49) y-=32;
if(x>y){
printf("1");
return 0;
}
if(x<y){
printf("-1");
return 0;
}
}
printf("0");
return 0;
}
P4213. 最小结果
可以发现总方案数很少,为
C
4
2
⋅
C
3
2
⋅
C
2
2
=
18
C_4^2\cdot C_3^2\cdot C_2^2=18
C42⋅C32⋅C22=18种,直接dfs即可
搜索时按照前序遍历搜,用vector存,可支持变长,选完任意两个数后,每次新开一个vector,添加剩余的数以及这两个数计算的结果
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long LL;
LL ans=1e18;
char op[3];
void dfs(vector<LL> v,int u){//当前用到了第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);
for(int i=0;i<4;i++) scanf("%lld",&v[i]);
for(int i=0;i<3;i++) scanf("%s",&op[i]);//因为有空格,建议直接用字符串
dfs(v,0);
printf("%lld",ans);
return 0;
}
为什么不用恢复现场? 每次我们是新开了一个t数组来存储当前所有数,不管t数组怎么变,都不会影响到一开始的v数组;如果我们在一开始给v加个引用,每次直接在v上面进行操作,就需要恢复现场,如下图:
P4214. 三元组
正解为状态机dp,较麻烦,这里讲怎么枚举,如果用三重循环来枚举的话会超时,需要优化
考虑枚举j,
S
i
S_i
Si只要小于
S
j
S_j
Sj即可,跟
S
k
S_k
Sk没有关系,
S
k
S_k
Sk同理,所以i和k是相互独立的,我们只要分别求出
C
i
C_i
Ci和
C
k
C_k
Ck的最小值,然后三项相加即可
结论一般化:若要求f(x)+g(y)+h(z),如果三项独立,我们只要让三项分别取最值相加,如果不独立就需要一层一层枚举了
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=3010,INF=3e8+10;
int n;
int s[N],c[N];
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++) scanf("%d",&s[i]);
for(int i=0;i<n;i++) scanf("%d",&c[i]);
int res=INF;
for(int j=0;j<n;j++){
int left=INF;
for(int 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[j]<s[k]) right=min(right,c[k]);
}
res=min(res,left+c[j]+right);
}
if(res==INF) printf("-1");
else printf("%d",res);
return 0;
}