AtCoder Beginner Contest 388(补题)

AtCoder Beginner Contest 388(补题)

整体如果比上次多做一个题叫进步的话,那还是有点进步的。

C - Various Kagamimochi

https://atcoder.jp/contests/abc388/tasks/abc388_c

思路(Trick)

因为序列是有序的,所以从左到右枚举每一个 i ,找到第一个大于等于 2*i 的数,此数和右边所有的数都满足条件。简单计数即可。

代码1:二分法 O(n * log n)

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n;
std::cin >> n;
std::vector<i64> v(n+1);
for (int i = 1; i <= n; i++) std::cin >> v[i];
i64 ans = 0;
for (int i = 1; i <= n; i++){
int a = v[i];
int pos = std::lower_bound(v.begin()+1, v.end(), a * 2) - v.begin();
ans += n - pos + 1;
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

代码2:双指针 O(n)

#include<bits/stdc++.h>
using namespace std;
const int N=6e5+5,N1=3e5+5;
int n,a[N],s,t,f[N],dis[N],is[N];
vector<int>ve[N];
bool vis[N];
/*int gcd(int x,int y){//最大公因数
if(x%y==0)return y;
else return gcd(y,x%y);
}*/void init(int n){
for(int i=2;i <=n; i++)
is[i]= true;
for(int i=2;i<=n;i++){
if(!is[i])continue ;
for(int j=i*2;j<= n;j += i){
is[j]= false;
}
}
}
int main(){
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
int l = 1, r = 1;
long long ans = 0;
while (l <= n) {
while (r <= n && a[r] < a[l] * 2) r++;
ans += n - r + 1;
l++;
}
cout << ans << endl;
return 0;
}

D - Coming of Age Celebration

https://atcoder.jp/contests/abc388/tasks/abc388_d

思路(差分)

此题分为接收石头和传递石头两个过程,考虑接收的石头的时候要知道左边的石头是怎样传递的,所以我们直接思考传递石头。

假设 i 位置在接收完石头后有 a_i 个,则说明他要向右传递 min(a_i, n - i)个石头,一个位置一个,最终结果是对一个区间做了+1操作。但是我们在计算一个位置向右传递多少石头时需要先接收石头,接收石头很明显对应差分的结算操作,结算完后又要向右修改,但是差分只能等所有修改都结束后才能结算,所以差分貌似是不可行的。我们再仔细思考一下。

差分的确是要修改完后再通过前缀和结算,但是这里的情况是,当我们使用前缀和结算到一个位置时,他的值已经确定了,不会再改变,所以是满足差分的性质的。

所以这道题的做法就是边用差分边修改边结算。

评述

本次最大遗憾,明明想到了差分但是把题想成了边改边结算的题,所以没有实现。

代码

#include <bits/stdc++.h>
typedef std::pair<long long, long long> pll;
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n;
std::cin >> n;
std::vector<int> v(n+1);
for (int i = 1; i <= n; i++) std::cin >> v[i];
std::vector<int> d(n+1);
for (int i = 1; i <= n; i++){
// 前缀和
d[i] += d[i-1];
v[i] += d[i];
// 差分
int t = std::min(v[i], n-i);
v[i] -= t;
d[i+1] += 1;
d[i+1+t] -= 1;
std::cout << v[i] << ' ';
}
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

E - Simultaneous Kagamimochi

https://atcoder.jp/contests/abc388/tasks/abc388_e

思路(二分)

假设同时做 i 个蛋糕可行,那么同时做 i - 1 个蛋糕很明显是可行的,所以这道题满足单调性,可以使用二分法。现在要解决的无非就是check函数。

我们可以贪心的想,对于一个序列我们能做 i 个蛋糕,做我们一定是拿这个序列最小的 i 个数和最大的 i 个数做尝试。接下来看代码就行。

代码

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e6 + 5;
int d[maxn], a[maxn];
int n;
bool check(int x) {
for (int i = 1; i <= x; i++) {
if (a[i] * 2 > a[n - x + i]) return false;
}
return true;
}
int main(){
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
sort(a + 1, a + 1 + n);
int l = 0, r = n / 2;
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid)) l = mid;
else r = mid - 1;
}
cout << l << endl;
return 0;
}

本文作者:califeee

本文链接:https://www.cnblogs.com/califeee/p/18666374

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   califeee  阅读(157)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.