2244: [SDOI2011]拦截导弹
Time Limit: 30 Sec Memory Limit: 512 MBSec Special Judge
Submit: 689 Solved: 277
[Submit][Status][Discuss]
Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。
Input
第一行包含一个正整数n,表示敌军导弹数量;
下面 行按顺序给出了敌军所有导弹信息:
第i+1行包含2个正整数hi和vi,分别表示第 枚导弹的高度和速度。
Output
输出包含两行。
第一行为一个正整数,表示最多能拦截掉的导弹数量;
第二行包含n个0到1之间的实数,第i个数字表示第i枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。
Sample Input
4
3 30
4 40
6 60
3 30
Sample Output
2
0.33333 0.33333 0.33333 1.00000
【数据规模和约定】
对于100%的数据,1≤n≤5*104, 1≤hi ,vi≤109;
均匀分布着约30%的数据,所有vi均相等。
均匀分布着约50%的数据,满足1≤hi ,vi≤1000。
HINT
鸣谢kac提供sj程序!
Source
第一轮day2
CDQ分治 我就直接写sort了…O(n log^2 n)
分别求以i结尾和开头的最长不上升子序列长度f1、f2和方案数g1、g2。这样概率就是g1[i]*g2[i]/总方案数,前提是f1+f2-1==ans,否则概率为0。
先求以i结尾的最长不上升子序列长度和方案数。
实现时可以转化成最长不下降子序列,这样方便用树状数组求。
solve(l,r)
Step1 按时间排序,solve(l,mid);
Step2 按y(高度)排序,用树状数组维护z(速度),计算x(时间)<=mid对x>mid的贡献。在树状数组上同时维护长度和方案数。
notice:
inline bool operator <(const data &b) const {
return y<b.y || y==b.y && z<b.z || y==b.y && z==b.z && x<b.x;
}
Step3 按时间排序,solve(mid+1,r);
还有方案数会很大,不能用long long,要用double。
可是bzoj上过的程序在codevs上并不能过,只能95..试了long double也不行
然后看了下别人的程序,发现在统计总方案数时换了一个我觉得并没有什么区别的写法就对了..并不知道为什么..而且用long double竟然会错QwQ
BZOJ
#include <bits/stdc++.h>
#define N 100010
using namespace std;
int n,a[N],cnt(0),b[N],cnt_(0),f[N];
double g[N];
struct data{
int x,y,z,mx,f; double num;
inline bool operator <(const data &b) const {
return y<b.y || y==b.y && z<b.z || y==b.y && z==b.z && x<b.x;
}
}q[N],q_[N];
inline bool cmp(const data &a,const data &b){
return a.x<b.x;
}
template <class Aqua>
inline void read(Aqua &s){
s=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) s=s*10+c-'0',c=getchar();
}
namespace BIT{
struct tree{
int mx; double num;
tree(){
mx=num=0;
}
}t[N];
tree query(int x){
tree ans;
for (;x;x-=x&(-x)){
if (t[x].mx>ans.mx)
ans.mx=t[x].mx,ans.num=0;
if (t[x].mx==ans.mx)
ans.num+=t[x].num;
}
return ans;
}
void update(int x,int d,double num){
for (;x<=cnt;x+=x&(-x)){
if (d>t[x].mx)
t[x].mx=d,t[x].num=0;
if (d==t[x].mx)
t[x].num+=num;
}
}
void clear(int x){
for (;x<=cnt;x+=x&(-x))
t[x].mx=t[x].num=0;
}
}
void solve(int l,int r){
if (l==r)
return;
int mid=l+r>>1;
solve(l,mid);
sort(q+l,q+1+r);
using namespace BIT;
tree ans;
for (int i=l;i<=r;i++){
if (q[i].x<=mid)
update(q[i].z,q[i].mx,q[i].num);
else{
ans=query(q[i].z); ans.mx++;
if (ans.mx>q[i].mx)
q[i].mx=ans.mx,q[i].num=0;
if (ans.mx==q[i].mx)
q[i].num+=ans.num;
}
}
for (int i=l;i<=r;i++)
if (q[i].x<=mid)
clear(q[i].z);
sort(q+l,q+1+r,cmp);
solve(mid+1,r);
}
int main(){
read(n);
for (int i=1;i<=n;i++){
q[i].x=i,read(q[i].y),read(q[i].z);
a[++cnt]=q[i].z; b[++cnt_]=q[i].y;
q[i].num=q[i].mx=1;
}
sort(a+1,a+1+cnt); sort(b+1,b+1+cnt_);
cnt=unique(a+1,a+1+cnt)-a-1;
cnt_=unique(b+1,b+1+cnt_)-b-1;
for (int i=1;i<=n;i++)
q[i].z=cnt-(lower_bound(a+1,a+1+cnt,q[i].z)-a)+1,
q[i].y=cnt_-(lower_bound(b+1,b+1+cnt_,q[i].y)-b)+1;
solve(1,n);
sort(q+1,q+1+n,cmp);
for (int i=1;i<=n;i++)
f[i]=q[i].mx,g[i]=q[i].num;
for (int i=1;i<=n;i++)
q[i].x=n-q[i].x+1,q[i].z=cnt-q[i].z+1,q[i].y=cnt_-q[i].y+1,
q[i].num=q[i].mx=1;
reverse(q+1,q+1+n);
solve(1,n);
for (int i=1;i<=n;i++)
q[i].x=n-q[i].x+1;
sort(q+1,q+1+n,cmp);
int ans=0; double sum=0;
for (int i=1;i<=n;i++){
if (f[i]>ans)
ans=f[i],sum=0;
if (f[i]==ans)
sum+=g[i];
}
printf("%d\n",ans);
for (int i=1;i<=n;i++)
g[i]=(q[i].mx+f[i]!=ans+1)?0:g[i]*q[i].num;
for (int i=1;i<n;i++)
printf("%.5lf ",g[i]/sum);
printf("%.5lf\n",g[n]/sum);
return 0;
}
Codevs
#include <bits/stdc++.h>
#define N 100010
using namespace std;
int n,a[N],cnt(0),b[N],cnt_(0),f[N];
double g[N];
struct data{
int x,y,z,mx,f; double num;
inline bool operator <(const data &b) const {
return y<b.y || y==b.y && z<b.z || y==b.y && z==b.z && x<b.x;
}
}q[N],q_[N];
inline bool cmp(const data &a,const data &b){
return a.x<b.x;
}
template <class Aqua>
inline void read(Aqua &s){
s=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) s=s*10+c-'0',c=getchar();
}
namespace BIT{
struct tree{
int mx; double num;
tree(){
mx=num=0;
}
}t[N];
tree query(int x){
tree ans;
for (;x;x-=x&(-x)){
if (t[x].mx>ans.mx)
ans.mx=t[x].mx,ans.num=0;
if (t[x].mx==ans.mx)
ans.num+=t[x].num;
}
return ans;
}
void update(int x,int d,double num){
for (;x<=cnt;x+=x&(-x)){
if (d>t[x].mx)
t[x].mx=d,t[x].num=0;
if (d==t[x].mx)
t[x].num+=num;
}
}
void clear(int x){
for (;x<=cnt;x+=x&(-x))
t[x].mx=t[x].num=0;
}
}
void solve(int l,int r){
if (l==r)
return;
int mid=l+r>>1;
solve(l,mid);
sort(q+l,q+1+r);
using namespace BIT;
tree ans;
for (int i=l;i<=r;i++){
if (q[i].x<=mid)
update(q[i].z,q[i].mx,q[i].num);
else{
ans=query(q[i].z); ans.mx++;
if (ans.mx>q[i].mx)
q[i].mx=ans.mx,q[i].num=0;
if (ans.mx==q[i].mx)
q[i].num+=ans.num;
}
}
for (int i=l;i<=r;i++)
if (q[i].x<=mid)
clear(q[i].z);
sort(q+l,q+1+r,cmp);
solve(mid+1,r);
}
int main(){
read(n);
for (int i=1;i<=n;i++){
q[i].x=i,read(q[i].y),read(q[i].z);
a[++cnt]=q[i].z; b[++cnt_]=q[i].y;
q[i].num=q[i].mx=1;
}
sort(a+1,a+1+cnt); sort(b+1,b+1+cnt_);
cnt=unique(a+1,a+1+cnt)-a-1;
cnt_=unique(b+1,b+1+cnt_)-b-1;
for (int i=1;i<=n;i++)
q[i].z=cnt-(lower_bound(a+1,a+1+cnt,q[i].z)-a)+1,
q[i].y=cnt_-(lower_bound(b+1,b+1+cnt_,q[i].y)-b)+1;
solve(1,n);
sort(q+1,q+1+n,cmp);
for (int i=1;i<=n;i++)
f[i]=q[i].mx,g[i]=q[i].num;
for (int i=1;i<=n;i++)
q[i].x=n-q[i].x+1,q[i].z=cnt-q[i].z+1,q[i].y=cnt_-q[i].y+1,
q[i].num=q[i].mx=1;
reverse(q+1,q+1+n);
solve(1,n);
for (int i=1;i<=n;i++)
q[i].x=n-q[i].x+1;
sort(q+1,q+1+n,cmp);
int ans=0; double sum=0;
for (int i=1;i<=n;i++){
int x=q[i].mx+f[i]-1;
g[i]*=q[i].num;
if (x>ans)
ans=x,sum=0;
if (x==ans)
sum+=g[i];
}
sum/=(double)ans;
printf("%d\n",ans);
for (int i=1;i<=n;i++)
if (q[i].mx+f[i]!=ans+1)
g[i]=0;
for (int i=1;i<n;i++)
printf("%.5lf ",g[i]/sum);
printf("%.5lf\n",g[n]/sum);
return 0;
}