AtCoder Beginner Contest 388(补题)
AtCoder Beginner Contest 388(补题)
整体如果比上次多做一个题叫进步的话,那还是有点进步的。
C - Various Kagamimochi
思路(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
思路(差分)
此题分为接收石头和传递石头两个过程,考虑接收的石头的时候要知道左边的石头是怎样传递的,所以我们直接思考传递石头。
假设 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
思路(二分)
假设同时做 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 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步