Link:
很简单的一场比赛打崩了也是菜得令人无话可说……
D:
一眼二分,发现对于固定的半径和点,能包含该点的圆的圆心一定在一个区间内,求出区间判断即可
此题一个重要性质就是圆与$x$轴相切,画出圆心所在直线后就能想到上述贪心了
#include <bits/stdc++.h> using namespace std; #define X first #define Y second #define pb push_back typedef double db; typedef long long ll; typedef pair<db,db> P; const db eps=1e-7; const int MAXN=1e5+10; struct Data{db l,r;int id;}a[MAXN]; int n,cnt1,cnt2;P dat[MAXN]; bool cmp(Data a,Data b) {return a.l<b.l;} db sqr(db x){return 1.0*x*x;} bool cal(db r,int k) { db b=2*dat[k].X; db c=sqr(dat[k].X)+sqr(dat[k].Y-r)-sqr(r); if(sqr(b)-4*c<-eps) return false; a[k].id=k; a[k].l=(b-sqrt(sqr(b)-4*c))/2.0; a[k].r=(b+sqrt(sqr(b)-4*c))/2.0; return true; } bool check(db r) { if(cnt1) r=-r; for(int i=1;i<=n;i++) if(!cal(r,i)) return false; db mn=1e60,mx=-1e60; for(int i=1;i<=n;i++) mn=min(mn,a[i].r),mx=max(mx,a[i].l); return mx<=mn; } int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%lf%lf",&dat[i].X,&dat[i].Y); cnt1+=dat[i].Y<0;cnt2+=dat[i].Y>0; } if(n==1) return printf("%.6lf",dat[1].Y/2.0),0; if(cnt1&&cnt2) return puts("-1"),0; //实数二分最好直接枚举次数,否则精度可能不够 // 也可以相对误差和eps比较 db l=0,r=1e16; for(int i=1;i<=200;i++) { db mid=(l+r)/2.0; if(check(mid)) r=mid; else l=mid; } printf("%.6lf",l); return 0; }
做的时候先想的凸包,想到正解后把一个$int$开成$double$后调不出来……
所以发现输出全是整数时要敏感啊……
注意:实数二分不用$fabs(l-r)$,会爆精度,最好卡次数
E:
可以先预处理每个点向上走的最远距离在树上$dp$,
不过其实直接从低向上贪心走就好了,在之前被走过的点就不用走了
可以并查集维护也可以直接暴力走
#include <bits/stdc++.h> using namespace std; #define X first #define Y second #define pb push_back typedef double db; typedef long long ll; typedef pair<int,int> P; const int MAXN=2e5+10; ll S,w[MAXN],pre[MAXN],res; int n,L,f[MAXN],ufs[MAXN],vis[MAXN],dep[MAXN],out[MAXN]; int find(int x) {return x==ufs[x]?x:find(ufs[x]);} int main() { scanf("%d%d%lld",&n,&L,&S); for(int i=1;i<=n;i++) scanf("%lld",&w[i]); for(int i=2;i<=n;i++) scanf("%d",&f[i]),out[f[i]]++; for(int i=1;i<=n;i++) { ufs[i]=i; if(w[i]>S) return puts("-1"),0; } for(int i=1;i<=n;i++) dep[i]=dep[f[i]]+1,pre[i]=pre[f[i]]+w[i]; queue<int> q; for(int i=1;i<=n;i++) if(!out[i]) q.push(i); while(!q.empty()) { int t=q.front();q.pop(); if(vis[t]) continue; int cur=t;res++; int len=0;ll sum=0; while(len<=L&&sum<=S) { int nxt=find(cur); len+=dep[cur]-dep[nxt]+1; sum+=pre[cur]-pre[nxt]+w[nxt]; if(len>L||sum>S) break; vis[nxt]=1;if(!f[nxt]) break; ufs[nxt]=find(f[nxt]);out[f[nxt]]--; if(!out[f[nxt]]&&!vis[f[nxt]]) q.push(f[nxt]); cur=f[nxt]; } } printf("%lld",res); return 0; }
以后做完签到题后把所有题先看一遍再决定顺序!