1.观前提醒
本人码力极差,码风不好,不喜勿喷。
2.T1 粮仓 rice(CF 785C)
CF 785C on Luoguhttps://www.luogu.com.cn/problem/CF785CCF 785C on CQBZOJ
https://43.139.55.23/contest/4546/problem/1
40pts code
首先贴上我的 40pts 代码:
#include<bits/stdc++.h>
#define int long long
int maxrice,dayrice,days,nowrice;
using namespace std;
signed main(){
//freopen("rice.in","r",stdin);
//freopen("rice.out","w",stdout);
scanf("%lld%lld",&maxrice,&dayrice);
nowrice=maxrice;
for(int i=1;;i++){
if(nowrice==maxrice)nowrice+=0;
else if(maxrice-nowrice<dayrice)nowrice=maxrice;
else nowrice+=dayrice;
nowrice-=i;
if(nowrice<=0){
days++;break;
}
else days++;
}
cout<<days;
return 0;
}
但是TLE了,因为数据范围最大到,所以暴力是肯定不行的。
Solution
对于前天而言,由于每次调走的谷物都会在第二天补满,因此,这些天并不会造成谷物的损失,从第
天开始,谷物的总量才会减少。对于第
天而言,谷物总计减少
了个,第天往后谷物总共减少了
,因为第
天开始,总量变为了
,所以,只需要求解
中的
的最小值即可。
注意:在计算过程中,需要先判断和
的相对大小,如果
小于等于
,直接输出
即可。
AC code
#include<bits/stdc++.h>
using namespace std;
long long n,m,ans;
int main(){
//freopen("rice.in","r",stdin);
//freopen("rice.out","w",stdout);
cin>>n>>m;
if(m>=n){
cout<<n;
return 0;
}
long long s=n-m-1,s1=0;
if(s>1000006280){
s1=1000006280;
ans=44720;
for(long long i=44722;s1<s;i++){
s1+=i;
ans++;
if(s1>=s)break;
}
cout<<ans+m+1;
return 0;
}
for(long long i=2;s1<s;i++){
s1+=i;
ans++;
if(s1>=s)break;
}
cout<<ans+m+1;
return 0;
}
3.T2 盒子与球 ball(Atcoder ABC214E)
AT_abc214_e on Luoguhttps://www.luogu.com.cn/problem/AT_abc214_eAT_abc214_e onCQBZOJ
https://43.139.55.23/contest/4546/problem/2
Solution
因为每个球能够放在一个指定的区间范围内中的任意一个位置,这里假设按照从左往右的顺序来进行插入小球。对于每一个小球而言,为了使得让尽可能多的后续的小球能够放到指定位置上,因此,我们就需要将这个小球放在尽可能靠左的位置。
因此,这里利用贪心的思想,先对所有的球能够放的范围按照左端点从小到大进行排序,再把排序后的内容按照右端点大小设置一个优先队列。每次计算时,从小到大枚举左端点,然后,将所有新的
符合要求的小球全部放入优先队列中,再然后,pop出一个小球出来放在当前
的位置。此时,判断,当前退出的这个
最小的球是否大于等于当前
,如果大于等于,则说明可以放,则继续枚举下一个
,否则,退出循环并输出
。当所有小球全部计算完都符合要求后,则输出
。
注意:别忘了要计算最后一个小球。
AC code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
struct Sec {
int l, r;
} a[N];
int n;
int main () {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int T; cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i].l >> a[i].r;
stable_sort(a+1, a+n+1, [&](Sec p, Sec q){ return p.l ^ q.l ? p.l < q.l : p.r < q.r; });
priority_queue<int, vector<int>, greater<int>> q;
int l, r = 0; bool ans = 1;
while (r < n || !q.empty()) {
if (q.empty())
l = a[++r].l,
q.push(a[r].r);
while (r < n && a[r+1].l <= l)
q.push(a[++r].r);
if (q.top() < l) { ans = 0; break; }
q.pop(), l++;
}
cout << (ans ? "Yes" : "No") << '\n';
}
return 0;
}
4.T3 兼容数字 compat(CF 165E)
CF165E on Luoguhttps://www.luogu.com.cn/problem/CF165ECF165E on CQBZOJ
https://43.139.55.23/contest/4546/problem/3
Solution
对于每一对 &
,若
与 的二进制表示中有同一位均为
,那么
&
的这一位也会为1 。因此可以发现,
是
按位取反后的子集。
50pts
对于每一个询问,枚举按位取反的数字的子集,判断数列中是否存在某个子集。
最差情况下复杂度:。
100pts
-
枚举子集的过程中,涉及很多重复计算,小小的加一个记忆化,dfs找可行子集即可搞定。
-
如果枚举
按位取反的数字为
,那么任意
的子集都能作为备选答案。那么可以从小到大预处理每个数字是否有子集在数列中存在。因为输出任意一个数即可,所以我们可以看成求满足
的最大数,即
,这个使用高维前缀和维护即可。
复杂度:
AC code
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define int long long
using namespace std;
const int N = 1e6 + 5;
const int logn = 22;
int n, a[N], f[1 << logn];
signed main() {
ios::sync_with_stdio(0);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for(int i = 1; i <= n; i++)
cin >> a[i], f[a[i]] = a[i];
for(int i = 0; i < logn; i++) {
for(int j = 0; j < (1 << logn); j++) {
if((j & (1 << i)) && f[j ^ (1 << i)]) f[j] = f[j ^ (1 << i)];
}
}
for(int i = 1; i <= n; i++) {
int XOR = ((1 << logn) - 1) ^ a[i];
cout << (f[XOR] ? f[XOR] : -1) << ' ';
}
}