题解 P5617 【[MtOI2019]不可视境界线】
disangan233 · · 题解
算法一
考虑
也有另外一种方法。考虑题目圆心都在
具体做法为用
令
怎么样?这个式子是不是看着傻里傻气,又臭又长?考虑改进一下这个式子,采用向量叉积计算三角形面积即可。
可通过子任务
算法二
由
令
暴力转移,时间复杂度
发现对于
时间复杂度
算法三
考虑子任务
结合算法一、二,期望得分
算法四
发现
令
显然这个二阶导数计算量极大,本答案采用 symbolab 验证通过。
这里采用 GeoGebra 画图的方法帮助验证,令
考虑
采用反证法,假设
这个两个不等式同时取等时可以直接交换
移项后得到:
所以我们得到:
因为
另一种方法:显然
因为
因为此处是导数递减,求
时间复杂度
算法五
发现
- 为什么是凸的呢,因为增量单调的性质可以转化为四边形不等式,所以得证。
对于每一个圆加上一个
时间复杂度
算法六
考虑将算法四和算法五相结合,可以强行结合,期望得分
发现分治做法会破坏
但是二分栈的做法满足了相对顺序,也不受上一维的限制,且 wqs 二分的切线函数为一次函数,其导数为定值,不会破坏转移方程的决策单调性。
所以将二分栈和 wqs 二分结合起来即可。
时间复杂度
代码实现
#pragma GCC optimize(2,3,"Ofast","unroll-loops")
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register int
#define db double
#define in inline
namespace fast_io
{
char buf[1<<12],*p1=buf,*p2=buf,sr[1<<23],z[23],nc;int C=-1,Z=0,Bi=0;
in char gc() {return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<12,stdin),p1==p2)?EOF:*p1++;}
in ll read()
{
ll x=0,y=1;while(nc=gc(),(nc<48||nc>57)&&nc!=-1)if(nc==45)y=-1;Bi=1;
x=nc-48;while(nc=gc(),47<nc&&nc<58)x=(x<<3)+(x<<1)+(nc^48),Bi++;return x*y;
}
in db gf() {re a=read(),b=(nc!='.')?0:read();return (b?a+(db)b/pow(10,Bi):a);}
in int gs(char *s) {char c,*t=s;while(c=gc(),c<32);*s++=c;while(c=gc(),c>32)*s++=c;return s-t;}
in void ot() {fwrite(sr,1,C+1,stdout);C=-1;}
in void flush() {if(C>1<<22) ot();}
template <typename T>
in void write(T x,char t)
{
re y=0;if(x<0)y=1,x=-x;while(z[++Z]=x%10+48,x/=10);
if(y)z[++Z]='-';while(sr[++C]=z[Z],--Z);sr[++C]=t;flush();
}
in void write(char *s) {re l=strlen(s);for(re i=0;i<l;i++)sr[++C]=*s++;sr[++C]='\n';flush();}
};
using namespace fast_io;
const int N=1e5+5,R=1e4+5;
const db pi=acos(-1),eps=1e-9;
int n,k,nr,a[N],g[N],p[N],q[N];
db f[N],ans,cur,dat[R<<1],s0,mid;
in db s(re i,re j) {return (a[j]-a[i]>=2*nr)?0:dat[a[j]-a[i]];}
in int find(re i,re j)
{
re l=j,r=n+1,m;
while(l<r) {m=(l+r)>>1;(f[i]-s(i,m)<=f[j]-s(j,m))?r=m:l=m+1;}
return l;
}
void dp(db mid)
{
for(re i=1,h=0,t=0;f[i]=g[i]=0,i<=n;i++)
{
while(h<t&&p[h]<=i) h++;
f[i]=f[q[h]]+s0-s(q[h],i)-mid;g[i]=g[q[h]]+1;
while(h<t&&p[t-1]>=find(q[t],i)) t--;
p[t]=find(q[t],i);q[++t]=i;
}
}
int main()
{
n=read();k=read();nr=read();s0=pi*nr*nr;
for(re i=0;i<2*nr;i++) {db tmp=2*acos(i/(2.0*nr));dat[i]=(tmp-sin(tmp))*nr*nr;}
a[0]=-1e9;for(re i=1;i<=n;i++) a[i]=read();
db l=0,r=s0;for(re i=1;i<=37&&r-l>5e-6;i++) {mid=(l+r)/2.0;dp(mid);(g[n]>k)?l=mid:r=mid;}
printf("%.8lf\n",f[n]+(l+r)*0.5*k);
return ot(),0;
}