ABC 314 GH 题解
没打,花了 10 分钟跟 piggy 用 qq 胡的做法:
G - Amulets
很明显的扫描线。
打到的怪物的编号是单调不减的,尝试增加怪物时平衡树找到 $B_i$ 的和最大的 $K$ 种颜色的 $B_i$ 的和,判断是否可以打败总伤害减去这个值即可。平衡树用 multiset 即可。
具体的:增加点的时候,如果在前 $K$ 个,加上自己的权值然后减一个权值,大于 $K$ 不变。第 $K$ 个值用一个指针保存。
$O(n \log m)$
部分代码:
void erase(ll x){
auto i=s1.find(x);
if(i!=s1.end())s1.erase(i),sum-=x,r--;
else s2.erase(s2.find(x));
}
void insert(ll x){
if(s1.size()){
auto i=s1.end();i--;
if(x>*i){
s1.insert(x),sum+=x,r++;
return;
}
}
s2.insert(x);
}
signed main(){
n=read(),m=read(),h=read();
rep(i,1,m)s2.insert(0);
r=0;
rep(i,1,n){
a[i]=read(),b[i]=read();
al+=a[i];
erase(c[b[i]]);
c[b[i]]+=a[i];
insert(c[b[i]]);
while(al-sum<h&&r){
auto it=s1.end();it--;
if(al-sum+*it>=h)break;
sum-=*it;
s2.insert(*it);
s1.erase(it);
r--;
}
while(al-sum>=h){
sum+=*s2.begin();
s1.insert(*s2.begin());
s2.erase(s2.begin());
r++;
}
p[i]=r;
}
rep(i,0,m)printf("%lld ",upper_bound(p+1,p+n+1,i)-p-1);
return 0;
}
Ex - Disk and Segments
题意就是找到距离 $n$ 条线段最近的一个点,模拟退火。
跟 P1337 类似,改改即可,感觉很板。
代码:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
inline double Rand(){
return (double)rand()/RAND_MAX;
}
struct node{
double x,y;
void in(){scanf("%lf%lf",&x,&y);}
}a[103],b[103];
node operator-(node x,node y){return {x.x-y.x,x.y-y.y};}
double len(node x){return sqrt(x.x*x.x+x.y*x.y);}
int dcmp(double x){return fabs(x)<1e-10?0:x<0?-1:1;}
double dot(node x,node y){return x.x*y.x+x.y*y.y;}
double cross(node x,node y){return x.x*y.y-x.y*y.x;}
double distoseg(node p,node a,node b){
node x=b-a,y=p-a,z=p-b;
if(dcmp(dot(x,y))<0)return len(y);
if(dcmp(dot(x,z))>0)return len(z);
return fabs(cross(x,y)/len(x));
}
int n;
double t,mn,sx,sy;
double get(double x,double y){
double ans=0;
rep(i,1,n)ans=max(ans,distoseg({x,y},a[i],b[i]));
if(ans<mn)mn=ans,sx=x,sy=y;
return ans;
}
signed main(){
srand((unsigned long long)new char);
scanf("%d",&n);
rep(i,1,n){
a[i].in(),b[i].in();
sx+=(a[i].x+b[i].x)/2.0,sy+=(a[i].y+b[i].y)/2.0;
}
sx/=n,sy/=n,mn=get(sx,sy);
t=1e3;
double nx=sx,ny=sy;
while(t>0.000001){
double x=nx+t*(Rand()*2-1),y=ny+t*(Rand()*2-1);
if(exp((get(nx,ny)-get(x,y))/t)>Rand())nx=x,ny=y;
t*=0.99995;
}
rep(i,1,100000){
double x=sx+t*(Rand()*2-1),y=sy+t*(Rand()*2-1);
get(x,y);
}
printf("%.8lf",mn);
return 0;
}