题目链接
分析:
这个导弹拦截好像不大一样
有高度有速度(还有数组下标)的限制
一个三维偏序的模型,可以用CDQ分治解决,复杂度 O(nlog2n) O ( n l o g 2 n )
但是这样只能求得LIS
而每个导弹被拦截的概率取决于ta存在于多少LIS中
ans=每个元素所在的LIS个数总LIS个数 a n s = 每 个 元 素 所 在 的 L I S 个 数 总 L I S 个 数
考虑更改一下dp
设 f[i] f [ i ] 表示以 i i 为结尾的最长非升子序列长度
g[i] g [ i ] 表示以 i i 为结尾的最长非升子序列方案数
h[i] h [ i ] 表示以 i i 为开头的最长非升子序列长度
s[i] s [ i ] 表示以 i i 为开头的最长非升子序列方案数
然后对于每一个 i i ,判断 f[i]+h[i]−1 f [ i ] + h [ i ] − 1 是否就是最长答案
如果是,那么 g[i]∗s[i] g [ i ] ∗ s [ i ] 就是这个点出现的次数
用两遍 CDQ C D Q 维护上述四个值
前辈好像都表示这道题就卡精度的风险
所以都用double即可
为什么会狂WA不止???
不知道,造了大数据跑了跑,也没什么问题
要是改,代码就又要面目全非了
(好不容易自己码风的CDQ,不想改了)
没错,想copy代码的同学肯定GG了
不过代码还是可以用来对拍的
b(bao)z(zou)oj。。。orz
#include
#include
#include
#include
#include
using namespace std;
const double eps=1e-8;
const int N=100010;
struct node{
int h,v,id,pos;
};
node a[N],b[N],p[N];
int n,V[N];
double f[N],g[N],h[N],s[N],c[N],d[N];
double maxf,maxg;
void hash() {
for (int i=1;i<=n;i++) V[i]=a[i].h;
sort(V+1,V+1+n);
int nn=unique(V+1,V+1+n)-V-1;
for (int i=1;i<=n;i++) a[i].h=lower_bound(V+1,V+1+nn,a[i].h)-V;
for (int i=1;i<=n;i++) V[i]=a[i].v;
sort(V+1,V+1+n);
nn=unique(V+1,V+1+n)-V-1;
for (int i=1;i<=n;i++) a[i].v=lower_bound(V+1,V+1+nn,a[i].v)-V;
}
int cmp0(const node &a,const node &b) {
return a.posint cmp1(const node &a,const node &b) {
return (a.h>b.h)||((a.h==b.h)&&(a.v>b.v));
}
int cmp2(const node &a,const node &b) {
return (a.hvoid add(int x,double z1,double z2) {
for (int i=x;i<=n;i+=(i&(-i)))
if (c[i]else if (c[i]==z1) d[i]+=z2;
}
void ask(int x) {
maxf=0; maxg=0;
for (int i=x;i>0;i-=(i&(-i)))
if (c[i]>maxf)
maxf=c[i],maxg=d[i];
else if (c[i]==maxf) maxg+=d[i];
}
void clear(int x) {
for (int i=x;i<=n;i+=(i&(-i)))
c[i]=0,d[i]=0;
}
void CDQ_a(int l,int r) { //以i结尾的最长下降子序列
if (l==r) return;
int mid=(l+r)>>1;
CDQ_a(l,mid);
int cnt=0;
for (int i=l;i<=r;i++) p[++cnt]=a[i]; //copy一下 不影响x坐标
sort(p+1,p+1+cnt,cmp1); //按照h排序(从大到小)
for (int i=1;i<=cnt;i++) //树状数组维护v
if (p[i].pos<=mid)
add(n-p[i].v+1,f[p[i].id],g[p[i].id]);
else {
ask(n-p[i].v+1);
if (f[p[i].id]1.0) {
f[p[i].id]=maxf+1.0;
g[p[i].id]=maxg;
}
else if (f[p[i].id]==maxf+1.0)
g[p[i].id]+=maxg;
}
for (int i=1;i<=cnt;i++)
if (p[i].pos<=mid) clear(n-p[i].v+1);
CDQ_a(mid+1,r);
}
void CDQ_b(int l,int r) { //以i开头的最长下降子序列
if (l==r) return;
int mid=(l+r)>>1;
CDQ_b(l,mid);
int cnt=0;
for (int i=l;i<=r;i++) p[++cnt]=b[i];
sort(p+1,p+1+cnt,cmp2);
for (int i=1;i<=cnt;i++)
if (p[i].pos<=mid)
add(p[i].v,h[p[i].id],s[p[i].id]);
else {
ask(p[i].v);
if (h[p[i].id]1.0) {
h[p[i].id]=maxf+1.0;
s[p[i].id]=maxg;
}
else if (h[p[i].id]==maxf+1.0)
s[p[i].id]+=maxg;
}
for (int i=1;i<=cnt;i++)
if (p[i].pos<=mid) clear(p[i].v);
CDQ_b(mid+1,r);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) { //正向
scanf("%d%d",&a[i].h,&a[i].v);
a[i].id=i; a[i].pos=i;
}
hash();
for (int i=1;i<=n;i++) { //逆向
b[i]=a[i]; b[i].pos=n-i+1;
}
sort(a+1,a+1+n,cmp0);
for (int i=1;i<=n;i++) f[i]=1.0,g[i]=1.0;
CDQ_a(1,n);
sort(b+1,b+1+n,cmp0);
for (int i=1;i<=n;i++) h[i]=1.0,s[i]=1.0;
CDQ_b(1,n);
double ans=0,tot=0;
for (int i=1;i<=n;i++) ans=max(ans,f[i]);
for (int i=1;i<=n;i++) if (f[i]==ans) tot+=g[i];
printf("%.0lf\n",ans);
for (int i=1;i<=n;i++)
if (f[i]+h[i]-1==ans)
printf("%.5lf%c",g[i]*s[i]/tot," \n"[i==n]);
else printf("%.5lf%c",0.0," \n"[i==n]);
return 0;
}