又有一段时间没打cf了,最近要找点强度,连一场找找感觉,做题时自信满满,然而在进击d题的过程中c题被hack了,导致分数--,还是好久没打手有点生了,细节考虑不周啊
A. Mind the Gap
思路:往时间表中插入事件,这就是一个典型的水题咯,暴力枚举初始时间和每件事发生后作为插入点
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
int main()
{
int n,s;
cin >> n >> s;
int h,m;
int nh,nm,neh,nem;
nh = 0;
nm = 0;
nem = (nm + s + 1) % 60;
neh = nh + (nm + s + 1) / 60;
bool ok = false;
for(int i=0;i<n;i++)
{
cin >> h >> m;
if(h>neh||(h==neh&&m>=nem))
{
cout << nh << " " << nm << endl;
ok = true;
break;
}
else
{
nm = (m + s + 1) % 60;
nh = h + (m + s + 1) / 60;
nem = (nm + s + 1) % 60;
neh = nh + (nm + s + 1) / 60;
}
}
if(!ok)
{
cout << nh << " " << nm << endl;
}
return 0;
}
B. Watering System
思路:堵最少的洞口使灌溉量达标,这个典型的贪心,每次堵最大洞判断即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
const double eps = 1e-6;
int s[maxn];
int main()
{
int n,A,B;
ios::sync_with_stdio(false);
cin >> n >> A >> B;
double sum = 0.0;
for(int i=0;i<n;i++)
{
cin >> s[i];
sum += s[i];
}
double need = (double)(s[0] * A) / (double)(B);
sort(s+1,s+n);
int pos = n;
//cout << need << " " << sum-eps << endl;
if(need < sum - eps)
{
for(pos=n-1;pos>0;pos--)
{
sum -= s[pos];
//cout << pos << "*" << sum << "*" << need-eps << endl;
if(sum <= need + eps)
{
break;
}
}
}
cout << n - pos << endl;
//cout << need << endl;
return 0;
}
C. Stairs and Elevators
思路:寻找最快回家方案,这题如果纯暴力明显tle,那就需要计算方案,思路其实也挺清晰,就是四种,两侧最近电梯和两侧最近楼梯都尝试一遍,取最优值,然而这题的坑点就在于如果两人同一层楼的话,就不需要经过电梯和楼梯就能直接到,这里被hack确实是自己的疏漏
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 1e5+10;
int ll[maxn];
int ee[maxn];
int myabs(int k)
{
if(k <0)
{
k *= (-1);
}
return k;
}
int main()
{
ios::sync_with_stdio(false);
//freopen("in.txt","r",stdin);
int n,m,cl,ce,v;
cin >> n >> m >> cl >> ce >> v;
for(int i=0;i<cl;i++)
{
cin >> ll[i];
}
for(int i=0;i<ce;i++)
{
cin >> ee[i];
}
int q;
cin >> q;
while(q--)
{
int x1,y1,x2,y2;
cin >> x1 >> y1 >> x2 >> y2;
if(y1 > y2)
{
int temp = y1;
y1 = y2;
y2 = temp;
temp = x1;
x1 = x2;
x2 = temp;
}
if(x1 == x2)
{
cout << y2 - y1 << endl;
continue;
}
int sum = 2e9 + 10;
int pos = lower_bound(ee,ee+ce,y1)-ee;
int pos2 = pos-1;
int hh = (myabs(x1-x2) - 1) / v + 1;
if(pos < ce)
{
if(ee[pos] < y2)
{
sum = y2 - y1 + hh;
//con = false;
//cout << "1*" << sum << endl;
}
else
{
int tempsum = ee[pos] - y2 + ee[pos] - y1 + hh;
//cout << "2*" << tempsum << endl;
if(tempsum < sum)
{
sum = tempsum;
}
}
}
if(pos2 >= 0)
{
int tempsum = y2 - ee[pos2] + y1 - ee[pos2] + hh;
//cout << "3*" << tempsum << endl;
if(tempsum < sum)
{
sum = tempsum;
}
}
pos = lower_bound(ll,ll+cl,y1)-ll;
pos2 = pos-1;
hh = myabs(x1-x2);
if(pos < cl)
{
if(ll[pos] < y2)
{
int tempsum = y2 - y1 + hh;
//cout << "4*" << tempsum << endl;
if(tempsum < sum)
{
sum = tempsum;
}
//con = false;
}
else
{
int tempsum = ll[pos] - y2 + ll[pos] - y1 + hh;
//cout << "5*" << tempsum << endl;
if(tempsum < sum)
{
sum = tempsum;
}
}
}
if(pos2 >= 0)
{
int tempsum = y2 - ll[pos2] + y1 - ll[pos2] + hh;
//cout << "6*" << tempsum << endl;
if(tempsum < sum)
{
sum = tempsum;
}
}
cout << sum << endl;
}
return 0;
}
D. Resource Distribution
思路:这题又是一个贪心,一开始的贪心策略是先处理大值,满足大值的情况下再处理小值,对于每次处理,暴力分的组数,采纳最小组数的结果
然而事实证明这种贪心策略是有漏洞的,由于整除性,完全可能小值占大位导致大值无处可占
于是想到统计每次占位的剩余值,保留最小剩余作为贪心策略,然而不好意思,维护剩余值的过程tle了
又想到只维护存在值,等结束后再统一处理,然而,有出问题了,存在大值占小位又wa了,无奈之下想出大数据直接贪心,小数据维护的玄学面向数据编程,成功过掉了这一题
当然,面上数据编程这样是不对的,本着学习而不是为了比赛的态度,重新研究了一波这题,正确的做法其实也不是很复杂,从前面的研究不难发现,之前的贪心策略过的数据特别多,只是少部分数据出了问题,那么就可以在原来贪心策略上进行改进
考虑到先贪心大数似乎没有足够的道理,而无论怎么贪心,贪心失败的结果也往往是一个数据占据了另一个数据本该有的位置,于是考虑到两次贪心,两个数各先贪心一次,若有成功方案即可
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cstring>
#include <map>
#include <cmath>
#include <string>
#include <queue>
#include <stack>
using namespace std;
const int maxn = 3e5+10;
const double eps = 1e-6;
map<int,vector<int> > pos;
map<int,int> num;
vector<int> rere1,rere2;
bool ccin[maxn];
int cc[maxn];
int cc0[maxn];
int main()
{
int n,x1,x2;
//freopen("in.txt","r",stdin);
ios::sync_with_stdio(false);
while(cin >> n >> x1 >> x2)
{
int re1,re2;
bool rev = false;
pos.clear();
num.clear();
rere1.clear();
rere2.clear();
memset(ccin,true,sizeof(ccin));
//double dif = 0;
for(int i=0;i<n;i++)
{
int temp;
cin >> temp;
pos[temp].push_back(i+1);
num[temp]++;
//dif += (double)(temp);
cc[i] = temp;
cc0[i] = temp;
}
sort(cc,cc+n);
/*if(x1<x2)
{
rev = true;
int temp = x2;
x2 = x1;
x1 = temp;
}*/
bool ok = false;
while(!ok)
{
if(rev)
{
pos.clear();
num.clear();
rere1.clear();
rere2.clear();
memset(ccin,true,sizeof(ccin));
pos.clear();
num.clear();
for(int i=0;i<n;i++)
{
int temp = cc0[i];
pos[temp].push_back(i+1);
num[temp]++;
}
sort(cc,cc+n);
}
int did;
int nownum = n-1;
int ti = 0;
//int dif = cc[n-1]+1;
int tempnownum;
//double tempsum = 0;
//int fi = n-1;
for(did=1;did<=n;did++)
{
double temp = (double)(x1) / (double)(did);
while(nownum>=0&&(/*(!ccin[nownum])||*/(temp-eps <= (double)(cc[nownum]))))
{
//cout << "&";
//if(ccin[nownum])
//{
ti++;
//tempsum += (double)(cc[nownum]);
//}
nownum--;
}
//cout << ti << "^^" << did << "^^"<< tempsum<< endl;
//cout << ti << "*" << did << "*" << nownum <<endl;
if(ti>=did)
{
while(ti>did)
{
//tempsum -= (double)(cc[fi]);
//fi--;
ti--;
}
//double tempdif = 0;
ok = true;
/*for(int i=0,j=nownum+1;i<did;i++,j++)
{
tempdif += cc[j] - (int)(temp);
// cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
}*/
//tempdif = tempsum - ceil(temp) * (double)(did);
//cout << tempdif << "&&" <<nownum << "&&" << did<< endl;
//if(tempdif < dif + eps)
//{
//dif = tempdif;
/*if(ok)
{
for(int i=0,j=tempnownum+1;i<re1;i++,j++)
{
int nowpos = cc[j];
rere1.clear();
// cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
num[nowpos] ++;
ccin[j] = true;
}
}
else
{
ok = true;
}
for(int i=0,j=nownum+1;i<did;i++,j++)
{
int nowpos = cc[j];
rere1.push_back(pos[nowpos][num[nowpos]-1]);
// cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
num[nowpos] --;
ccin[j] = false;
}*/
tempnownum = nownum;
re1 = did;
//}
/*if(n==4&&x1==12&&x2==11)
{
}
else
{*/
break;
//}
}
}
if(ok)
{
for(int i=0,j=tempnownum+1;i<re1;i++,j++)
{
int nowpos = cc[j];
rere1.push_back(pos[nowpos][num[nowpos]-1]);
// cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
num[nowpos] --;
ccin[j] = false;
}
ok = false;
nownum = n-1;
int ti = 0;
for(did=1;did<=n;did++)
{
double temp = (double)(x2) / (double)(did);
while(nownum>=0&&((!ccin[nownum])||(temp-eps <= cc[nownum])))
{
// cout << "&";
if(ccin[nownum])
{
ti++;
}
nownum--;
}
//cout << ti << "*" << did << "*" << nownum <<endl;
if(ti>=did)
{
ok = true;
re2 = did;
for(int i=0,j=nownum+1;i<did;i++,j++)
{
while(!ccin[j])
{
j++;
}
int nowpos = cc[j];
rere2.push_back(pos[nowpos][num[nowpos]-1]);
// cout << "#" << nowpos << "#" << num[nowpos] << "#" << pos[nowpos][num[nowpos]-1] << endl;
num[nowpos] --;
ccin[j] = false;
}
break;
}
}
}
if(ok||rev)
{
break;
}
else
{
rev = true;
int temp = x2;
x2 = x1;
x1 = temp;
}
}
if(ok)
{
if(rev)
{
cout << "Yes\n" << re2 << " " << re1 << "\n" << rere2[0];
for(int i=1;i<re2;i++)
{
cout << " " << rere2[i];
}
cout << "\n" << rere1[0];
for(int i=1;i<re1;i++)
{
cout << " " << rere1[i];
}
cout << endl;
}
else
{
cout << "Yes\n" << re1 << " " << re2 << "\n" << rere1[0];
for(int i=1;i<re1;i++)
{
cout << " " << rere1[i];
}
cout << "\n" << rere2[0];
for(int i=1;i<re2;i++)
{
cout << " " << rere2[i];
}
cout << "\n";
}
}
else
{
cout << "No\n";
}
}
return 0;
}
/*最小差值a
简化步骤
临界扩大化,随时检查数据范围
双向判断,简化步骤*/