JSOI2015 Round2 Day1

来源:互联网 发布:oracle sql语句 编辑:程序博客网 时间:2024/05/01 07:51

感觉还是好懒啊,这样看来一轮省选前肯定更不完辣。

T1:

T1就是一个裸的树状数组啊,预处理出来每位女士选择每位男士的可能行,然后按照女士为第一关键字,男士为第二关键字,排个序。扫描一遍,每次查询一下比当前男士大的和,再把这位女士选择这位男士的可能性插进去,总之没什么难度。

想要求出每位女士选择每位男士的可能性有两种方法,一是无穷数列求和,假设某位女士一共有n位可选择的男士,当前正在考虑的排名第m,那么就是:

这个数列显然收敛,求个和就好辣。

也可以这么想,第一轮成功牵手的为q=1-(1-p)^n,其中选择第i位男士的概率为q2=p*(1-p)^(i-1),答案就是q2/q。

貌似精度有问题,不过有SPJ(好像?)

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cstdlib>#define maxn 500010using namespace std;const double eps=1e-6;struct Node{int x,y;double dis;bool operator<(const Node &t)const{return x<t.x||(x==t.x&&y<t.y);}}A[maxn];bool cmp2(Node a,Node b){return a.x<b.x||(a.x==b.x&&a.y>b.y);}int n,m;double p;double exp[maxn],sm[maxn];double c[maxn];void add(int x,double y){for(;x<=n;x+=x&(-x))c[x]+=y;}double query(int x){double ans=0;for(;x;x-=x&(-x))ans+=c[x];return ans;}void Work(){double ans=0;for(int l=1,r=1;l<=m;l=r+1){while(A[r+1].x==A[l].x)r++;for(int j=1;j<=r-l+1;j++)A[l+j-1].dis=exp[j-1]*p/(1-exp[r-l+1]);}//sort(A+1,A+m+1,cmp2);for(int i=1;i<=m;i++){ans+=A[i].dis*(query(n)-query(A[i].y));add(A[i].y,A[i].dis);}printf("%.2lf\n",ans);}void Init(){scanf("%d%d",&n,&m);scanf("%lf",&p);exp[0]=1;for(int i=1;i<=m;i++)exp[i]=exp[i-1]*(1-p);for(int i=1;i<=m;i++)sm[i]=sm[i-1]+exp[i];for(int i=1;i<=m;i++)scanf("%d%d",&A[i].x,&A[i].y);sort(A+1,A+m+1);}int main(){freopen("cross.in","r",stdin);freopen("cross.out","w",stdout);Init();Work();return 0;}

T2:

一道贪心题,首先注意到最小化目标可以转化为最大化目标。我们把最小化空隙乘权值,转化为最大化每个的外径乘权值,这样子就可以贪心辣。

把外径从大到小排个序,每次考虑一个外径,选择一个可以选择的(内径严格大于它的)最大权值,然后删去这个内径,需要离散化一下。

正确性显然,若一个可以选择的较大权值y给了较大半径b,较小权值x给了较小半径a,那么by+ax>ay+bx可以有柯西不等式证明,交换不会取得更大的优势。

每次操作可以用线段树优化

代码:

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cstdlib>#define LL long long#define maxn 200010using namespace std;struct Node{int x,y,k;}A[maxn];struct Hash{int x,tp,id,V;bool operator<(const Hash &t)const{if(x!=t.x)return x<t.x;if(tp!=t.tp)return tp<t.tp;return id<t.id;}Hash(int x=0,int tp=0,int id=0,int V=0):x(x),tp(tp),id(id),V(V) {}}hash[maxn<<1];struct Tree{int l,r,mx;}T[maxn<<3];void build(int i,int l,int r){int M=l+r>>1;T[i].l=l;T[i].r=r;if(l==r){T[i].mx=hash[l].V;return;}build(i<<1,l,M);build(i<<1|1,M+1,r);T[i].mx=max(T[i<<1].mx,T[i<<1|1].mx);}int query(int i,int l,int r){int M=T[i].l+T[i].r>>1;if(l<=T[i].l&&r>=T[i].r)return T[i].mx;if(r<=M)return query(i<<1,l,r);if(l>M)return query(i<<1|1,l,r);return max(query(i<<1,l,r),query(i<<1|1,l,r));}void update(int i,int x,int t){int M=T[i].l+T[i].r>>1;if(T[i].l==T[i].r){T[i].mx=0;return;}if(T[i<<1|1].mx>=t)update(i<<1|1,x,t);else update(i<<1,x,t);T[i].mx=max(T[i<<1].mx,T[i<<1|1].mx);}int n,tot;void Work(){LL ans=0;for(int i=1;i<=n;i++)ans+=1LL*A[i].k*A[i].y;for(int i=tot;i;i--)if(hash[i].tp){int t=query(1,i+1,tot+1);//cout<<hash[i].x<<' '<<t<<endl;ans-=1LL*hash[i].x*t;update(1,i+1,t);}printf("%I64d\n",ans);}void Init(){scanf("%d",&n);for(int i=1;i<=n;i++){scanf("%d%d%d",&A[i].x,&A[i].y,&A[i].k);hash[++tot]=Hash(A[i].x,1,i,0);hash[++tot]=Hash(A[i].y,0,i,A[i].k);}sort(hash+1,hash+tot+1);build(1,1,tot+1);}int main(){freopen("doll.in","r",stdin);freopen("doll.out","w",stdout);Init();Work();return 0;}

T3:

T3我也没写啦啦啦。

我们来讲讲部分分吧,

20分部分分:

考虑左右端点,受三个值的影响,投影布的左右端点,光源角度,光线能跑的距离,三者搞一搞,搞出来一个范围,就好了,不能更水(坑)。

double r=tx;r=min(r,sqrt(max(len*len-ty*ty,0.0)));r=min(r,ty*tan(rnd(ang/2)));double l=sx;l=max(l,-sqrt(max(len*len-ty*ty,0.0)));l=max(l,-ty*tan(rnd(ang/2)));printf("%.4lf\n",(r-l)/(tx-sx));

40分;

为了这20分。。。

首先还是先求出左右端点,用的是上一个部分分的方法。

然后对于每一个墙,,求出左右端点的极角,映射到投影布所在的平面上,期间很多注意点。

比如不能向下映射,可能产生无穷,比如内区间还是外区间,反正这20分就不好拿辣。

某司机挂了20分,手动蜡烛。

void get_dang(int i){double r1,r2;r1=atan2(A[i].y1,A[i].x1);r2=atan2(A[i].y2,A[i].x2);if(r1>r2)swap(r1,r2);if(r1<-pi/2&&r2>pi/2)swap(r1,r2);if(r1<0&&r2<0)return;if(r1<0&&r2>0)r1=1e-5;if(r1>0&&r2<0)r2=pi-1e-5;double l=sy*tan(pi/2-r2),r=sy*tan(pi/2-r1);D[++cnt].l=l;D[cnt].r=r;}void Plan2(){double r=tx;r=min(r,sqrt(max(len*len-ty*ty,0.0)));r=min(r,ty*tan(rnd(ang/2)));double l=sx;l=max(l,-sqrt(max(len*len-ty*ty,0.0)));l=max(l,-ty*tan(rnd(ang/2)));for(int i=1;i<=n;i++)get_dang(i);for(int i=1;i<=cnt;i++)D[i].l=max(D[i].l,l),D[i].l=min(D[i].l,r),D[i].r=max(D[i].r,l),D[i].r=min(D[i].r,r);sort(D+1,D+cnt+1);double t=0,lst=-1e10;for(int i=1;i<=cnt;i++){if(D[i].l>lst)t+=D[i].r-D[i].l;else t+=D[i].r-lst;lst=D[i].r;}printf("%.4lf\n",(r-l-t)/(tx-sx));}

以下纯属口胡:

60pts,处理一面镜子就好辣

100pts:

我们将角度分成极小的一份份,每一份射出一条,记录他的经过反射和吸收的路线,如果相邻的两条光线经过的路径完全一样,我们就认为这一段区间内都完全一样,否则继续二分。

复杂度玄学,可以通过所有测试点。


1 0
原创粉丝点击