A - Setting up Camp
思路:判断c能否填充b让b为3的倍数
查看代码
void solve() {
int a,b,c;
cin>>a>>b>>c;
int ans=a+b/3;
b%=3;
if(b>0&&b+c<3)cout<<-1<<'\n';
else{
ans+=(b+c+2)/3;
cout<<ans<<'\n';
}
}
B - Fireworks
思路:同时开炮是最优的,计算在第一炮消失前a和b能发射的最大炮数
查看代码
void solve() {
int a,b,m;
cin>>a>>b>>m;
m++;
cout<<(m+a-1)/a+(m+b-1)/b<<'\n';
}
C - Left and Right Houses
思路:枚举分界线,同时维护左右的01个数
查看代码
void solve() {
int n;
string s;
cin>>n>>s;
double p=1e9;
int r=0,ans;
for(int i=0;i<s.size();++i){
if(s[i]=='1')r++;
}
for(int i=0,l=0;i<=n;++i){
if(l>=((i+1)/2)&&r>=((n-i+1)/2)){
double t=fabs(n*1.0/2-i);
if(!(fabs(t-p)<eps)&&t<p){
p=t,ans=i;
}
}
if(i<n)l+=(s[i]=='0'),r-=(s[i]=='1');
}
cout<<ans<<'\n';
}
D - Seraphim the Owl
思路:由于可以任选a,实际上就是最后要站在m内,且最后站的位置选a,后面的所有人ab取最小值
查看代码
void solve() {
int n, m;
cin>>n>>m;
vector<int>a(n+1),b(n+1),mi(n+1),r(n+5);
for(int i=1;i<=n;++i)cin>>a[i];
for(int i=1;i<=n;++i){
cin>>b[i];
mi[i]=min(a[i],b[i]);
}
for(int i=n;i>=1;--i)r[i]=r[i+1]+mi[i];
int res=LLONG_MAX;
for(int i=1;i<=m;++i){
res=min(res,a[i]+r[i+1]);
}
// if(n==m)res=0;
cout<<res<<'\n';
}
E - Binary Search
思路:模拟出原本数组二分x的位置,若与x原本位置不同交换即可
查看代码
void solve() {
int n,x,p;
cin>>n>>x;
vector<int>a(n+1);
for(int i=1;i<=n;++i){
cin>>a[i];
if(a[i]==x)p=i;
}
int l=1,r=n+1;
while(l+1<r){
int mid=l+r>>1;
if(a[mid]<=x)l=mid;
else r=mid;
}
if(l==p)cout<<0<<'\n';
else{
cout<<1<<'\n';
cout<<p<<' '<<l<<'\n';
}
}
F - Kirill and Mushrooms
思路:可以枚举选的个数k,不能选的数已经确定为前k-1个,用multiset维护剩下的可选的数,选出最大的k个数。若当前需要删的数在set里,直接在set里删即可,若不在说明在已选的数里删,还需要在set再选取一个数补回去。由于选的数是递减的,每选一次的数一定是最小的,直接维护其为最小值即可
查看代码
void solve() {
int n;
cin>>n;
multiset<int>q;
vector<int>a(n+1),b(n+1);
for(int i=1;i<=n;++i){
cin>>a[i];
q.insert(a[i]);
}
for(int i=1;i<=n;++i){
cin>>b[i];
}
int ans=*q.rbegin(),cnt=1,low=LLONG_MAX;
q.erase(q.find(*q.rbegin()));
for(int i=1;2*i+1<=n;++i){
auto p=q.lower_bound(a[b[i]]);
if(p!=q.end()){
q.erase(p);
low=*q.rbegin();
q.erase(q.find(*q.rbegin()));
}else{
q.erase(q.find(*q.rbegin()));
low=*q.rbegin();
q.erase(q.find(*q.rbegin()));
}
if(low*(i+1)>ans){
ans=low*(i+1),cnt=i+1;
}
}
cout<<ans<<' '<<cnt<<'\n';
}
G - Cook and Porridge
思路:由于原先的队列已定,并且不是按k排序的,需要将再次入队的与原先队列分开判断,再次入队的是按k排序,所以直接用优先队列维护即可。选取队首时,需要从原先队列队首和优先队列队首二选一,怎么选呢,对于原先队列求k的后缀最大值,只有当一个人的k大于原先队列队首的后缀最大值,其才能够插队到原先队列前,可以由此来判断优先队列队首是否能插到原先队列队首前面。对于正在吃饭的人,直接用优先队列维护吃完饭的时间即可。注意,在重新入队时,只有当入队时间相同时才用s来判断队列里的优先级
查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
//#define int __int128
#define double long double
typedef pair<int,int>PII;
typedef pair<string,int>PSI;
typedef pair<string,string>PSS;
const int N=4e4+5,INF=0x3f3f3f3f,Mod=1e9+7,mod=998244353;
const int MAXN=1e8+5;
const double eps=1e-12;
const int dx[4]={-1,1,0,0};
const int dy[4]={0,0,-1,1};
struct Eq{
int k,id,s,time;
bool operator<(const Eq&e)const{
if(k!=e.k)return k<e.k;
if(time!=e.time)return time>e.time;
return s>e.s;
}
};
struct Eh{
int t,id;
bool operator<(const Eh&e)const{
return t>e.t;
}
};
void solve() {
int n,D;
cin>>n>>D;
vector<int>k(n+1),s(n+1),r(n+1);
for(int i=1;i<=n;++i)cin>>k[i]>>s[i];
r[n]=k[n];
for(int i=n-1;i>0;--i)r[i]=max(r[i+1],k[i]);
priority_queue<Eq>q;
priority_queue<Eh>have;
int to=1;
for(int i=1;i<=D;++i){
if(q.size()){
auto f=q.top();
if(f.k>r[to]){
q.pop();
have.push({i+s[f.id],f.id});
}else{
have.push({i+s[to],to});
to++;
}
}else{
have.push({i+s[to],to});
to++;
}
if(to>n){
cout<<i<<'\n';
return ;
}
while(have.size()&&have.top().t<=i){
auto f=have.top();
have.pop();
q.push({k[f.id],f.id,s[f.id],i});
}
}
cout<<-1<<'\n';
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
// init();
while(t--){
solve();
}
return 0;
}
标签:const,int,void,Codeforces,cin,队列,solve,Div,935 From: https://www.cnblogs.com/bible-/p/18090306