蓝桥 周赛27 20250402
蓝桥 周赛27 20250402
https://www.lanqiao.cn/oj-contest/senior-27/
A:
题目大意:计算 \(\sum_{i=1}^{16}i\)
void solve(){
cout<<(1+16)*16/2;
}
签到
B:
题目大意:给定字符串 \(s\) ,求子串 lan
的个数
void solve(){
string s;
cin>>s;
LL l=0,la=0,lan=0;
for (int i=0;i<s.size();i++){
if (s[i]=='l')
l++;
if (s[i]=='a')
la+=l;
if (s[i]=='n')
lan+=la;
}
cout<<lan;
}
签到,线性DP
C:
题目大意:
struct nd{
LL a,b;
};
void solve(){
int n;
cin>>n;
vector<nd> x(n+10);
for (int i=1;i<=n;i++) cin>>x[i].a>>x[i].b;
sort(x.begin()+1,x.begin()+n+1,[](nd u,nd v){return u.a-u.b>v.a-v.b;});
LL sum=0;
for (int i=1;i<=n;i++){
if (i<=n/2) sum+=x[i].a;
else sum+=x[i].b;
}
cout<<sum;
}
一眼看过去以为是背包问题,其实可以模拟 \(O(n)\) 计算
对于每个酬劳而言,最优选择是选择 \(A_i,B_i\) 中最大的,所以对每个酬劳按照 \(A_i-B_i\) 排序,先让小红选
贪心的选择前 \(\lfloor n/2\rfloor\) 个酬劳的 \(A_i\) ,一定是最优解
D:
题目大意:
void solve(){
int n;
cin>>n;
vector<LL> a(n+10),b(n+10);
for (int i=1;i<=n;i++) cin>>b[i];
for (int i=1;i<=n;i++) cin>>a[i];
sort(b.begin()+1,b.begin()+n+1);
LL ans=0,sum=0;
for (int i=1;i<=n;i++)
ans+=b.begin()+n+1-upper_bound(b.begin()+i,b.begin()+n+1,a[i]);
cout<<ans;
}
有点神经,先输入的是蓝队而不是红队
因为红队队员按照给定的顺序出场,而我们可以自由选择蓝队成员出场,并且我们当前出场的蓝队队员只要比一个红队出场的队员大,那么胜场加一,每次上场的蓝队队员需要和每一个红队队员进行比较
所以,蓝队的最优策略是将较大的队员后上场,可以这样考虑:越后上场的蓝队队员能和越多的红队队员进行比较,那么就有越大的胜利场次,而将最大的队员放在最后可以最大程度的增加胜算
将蓝队队员按照大小进行排序后,考虑每个红队队员 \(a_i\) ,他只能被他之后上场或同时上场的蓝队队员赢
那么从当前红队队员上场编号开始进行二分,用 upper_bound
找到 \(i\) 之后的大于 \(a_i\) 的 \(b_j\) 的位置,从这个 \(b_j\) 开始,之后的 \(b_k\) 一定比 \(a_i\) 都要大,那么胜场数为 \(n-j+1\)
E:
题目大意:
const int mod=1e9+7;
void solve(){
int n,d;
cin>>n>>d;
unordered_map<int,vector<int>> mp;
for (int i=1;i<=n;i++){
int x;
cin>>x;
mp[x].push_back(i);
}
LL ans=1,t=0;
for (auto &it:mp){
auto v=it.second;
t=1+v.size();
for (int i=0;i<v.size();i++)
t=(t+(upper_bound(v.begin(),v.end(),v[i]+d)-(v.begin()+i)-1))%mod;
ans=(ans*t)%mod;
}
cout<<ans-1;
}
组合数学,每个国家都是互相独立的
那么用 unordered_map
存每个国家的位置,mp[x].push_back(i);
遍历每个国家的位置,从位置 \(i\) 向后找第一个大于 \(v_i+d\) 的位置 \(j\) ,那么 \(j-i-1\) 就是和 \(v_i\) 相距不超过 \(d\) 的座位数
因为选取距离小于 \(d\) 的两个座位是一个组合,那么只用考虑右侧的情况即可
所以对当前国家可以选取的方案数为 \(\sum(j-i-1)+n+1\) 即所有选两个的方案数加上只选一个和一个都不选的方案数
因为每个国家都是独立,考虑乘法原理对于所有的国家数 \(x\) ,方案数为 \(\prod_{i=1}^x ans_i\)
又因为题目要求不能一个都不选,所以最后需要减去 \(1\)
F:
题目大意:
void solve(){
int n,t;
cin>>n>>t;
vector<int> a(n+1),b(n+1);
for (int i=1;i<=n;i++) cin>>a[i];
for (int i=1;i<=n;i++) cin>>b[i];
b[n]=0;
int l=0,r=3600+1;
auto judge=[&](int x){
int dly=0,cnt=0,tim=x;
for (int i=1;i<=n;i++){
tim-=dly;
while (tim<a[i]){
tim+=x;
cnt++;
}
if (tim>x) tim=x;
tim-=a[i];
dly=b[i];
}
return cnt>=t;
};
while (l+1!=r){
int mid=l+r>>1;
if (judge(mid))
l=mid;
else
r=mid;
}
if (r==3601) cout<<-1;
else cout<<r;
}
二分+模拟
坑点在于 \(b_i\) 可能会持续多天,并且最后一天的 \(b_i\) 如果需要推迟到第二天那么也不用算
所以可以提前将 b[n]=0
,judge
函数写法有点牢
auto judge=[&](int x){
int dly=0,cnt=0,tim=x;
for (int i=1;i<=n;i++){
if (x<a[i]) return true;//如果当前的工作时间不能完成一天的任务,直接返回
tim-=dly;//减去当前需要的b_i,欠工作时间为负数
while (tim<a[i]){//剩余的工作时间不能完成,那么就推迟下一天
tim+=x;//补时间
cnt++;//天数+1
}
if (tim>x) tim=x;//最大时间不能超过x
tim-=a[i];
dly=b[i];
}
return cnt>=t;
};