太弱了,比赛时只出了A的大数据和BC小数据,排到1700+。赛后才把B的小数据过了。
A. Mushroom Monster
就是贪心模拟。第一种吃法,只有当前时刻比10秒前少才去吃减少的量,否则不吃。第二种吃法,计算每十秒的减少量,以减少量最大的作为平均速率去吃。
#include <bits/stdc++.h>
using namespace std;
int m[10010];
int main(){
freopen("A-large.in","r",stdin);
freopen("A-large.out","w",stdout);
int t;
cin>>t;
int x=0;
while(t--){
x++;
int n;
cin>>n;
for(int i=1;i<=n;i++){
scanf("%d",&m[i]);
}
int y=0;
int MAX_speed=0;
for(int i=2;i<=n;i++){
if(m[i]<m[i-1]){
y+=m[i-1]-m[i];
if(m[i-1]-m[i]>MAX_speed){
MAX_speed=m[i-1]-m[i];
}
}
}
int z=0;
for(int i=1;i<n;i++){
if(m[i]<MAX_speed){
z+=m[i];
}else{
z+=MAX_speed;
}
}
printf("Case #%d: %d %d\n",x,y,z);
}
return 0;
}
B. Haircut
建立一个优先队列去模拟,队列大小是理发师人数,每次有人理完发(pop),下一个人接着上(push)。解题关键在减小模拟的量,因为模拟n个人会超时。小数据可以求时间的公倍数,计算出公倍数时间能理的人数,用总人数模它。大数据则需要二分找一个接近理完但是没有理完的时间,从那个时间开始模拟。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int m[1010];
struct node{
int idx;
ll tot_time;
node(int idx,ll tot_time):idx(idx),tot_time(tot_time){
}
node(){
}
bool operator <(const node& other)const{
if(tot_time!=other.tot_time){
return tot_time>other.tot_time;
}
return idx>other.idx;
}
};
int main(){
freopen("B-large-practice.in","r",stdin);
freopen("B-large-practice.out","w",stdout);
int t;
cin>>t;
int cas=0;
while(t--){
cas++;
int b,n;
cin>>b>>n;
priority_queue<node> que;
ll MAX_time=0;
ll MIN_time=100000;
for(int i=1;i<=b;i++){
scanf("%d",&m[i]);
if(m[i]>MAX_time)MAX_time=m[i];
if(m[i]<MIN_time)MIN_time=m[i];
}
ll l=(n*MIN_time)/b-MAX_time;
ll r=(n*MAX_time)/b+MAX_time;
ll aTime=l;
while(l<=r){
ll mid=(l+r)>>1;
ll cnt=0;
for(int i=1;i<=b;i++){
cnt+=mid/m[i];
if(mid%m[i])cnt++;
if(cnt>=n)break;
}
if(cnt>=n){
r=mid-1;
}else{
l=mid+1;
aTime=mid;
}
}
ll cnt=0;
for(int i=1;i<=b;i++){
cnt+=aTime/m[i];
if(aTime%m[i])cnt++;
que.push( node(i, (m[i]-aTime%m[i])%m[i] ) );
}
for(int i=cnt+1;i<n;i++){
node cur=que.top(); que.pop();
que.push( node( cur.idx,cur.tot_time+m[cur.idx]) );
}
node ans=que.top();
printf("Case #%d: %d\n",cas,ans.idx);
}
return 0;
}
C. Logging
一看到凸包有点蒙了,不过解法貌似不需要凸包。小数据可以枚举每个点i,然后再枚举每个不同于i的点j,连接ij,用叉积计算直线两侧有多少点,取较小的那一侧,对所有j取最小值。这个结果就是为了使i在凸包上需要去掉的点数。大数据不会做。。。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
struct Point{
ll x,y;
Point(ll x,ll y):x(x),y(y){
}
Point(){
}
}pts[3010];
struct Vector{
ll x,y;
Vector(ll x,ll y):x(x),y(y){
}
Vector(){
}
Vector(Point A,Point B){
x=B.x-A.x;
y=B.y-A.y;
}
};
ll Cross(Vector A,Vector B){
return A.x*B.y - A.y*B.x;
}
int main(){
freopen("C-small-attempt2.in","r",stdin);
freopen("C-small-attempt2.out","w",stdout);
int t;
cin>>t;
int cas=0;
while(t--){
cas++;
int n;
cin>>n;
for(int i=1;i<=n;i++){
cin>>pts[i].x>>pts[i].y;
}
printf("Case #%d:\n",cas);
for(int i=1;i<=n;i++){
int ans=max(n-3,0);
for(int j=1;j<=n;j++){ //枚举
if(i==j)continue;
int left=0;
int right=0;
for(int k=1;k<=n;k++){
if(k==i)continue;
if(k==j)continue;
Vector v1 = Vector(pts[i],pts[j]);
Vector v2 = Vector(pts[i],pts[k]);
ll cp = Cross(v1,v2);
if(cp<0)left++;
if(cp>0)right++;
}
int tmp=min(left,right);
ans=min(ans,tmp);
}
cout<<ans<<endl;
}
}
return 0;
}