zoukankan      html  css  js  c++  java
  • test20190805 夏令营NOIP训练20

    100+0+0=100,由于第二题写挂rank 1就没了

    xyz现在站在一个斜坡面前
    这个斜坡上依次排布这n座山峰,xyz打算爬上其中的一座
    因为xyz体力不好,所以他只能爬上最矮的一座山
    又因为xyz不擅长分类讨论,因此即使山的海拔为负,他也只打算爬海拔最低的那座,而不是海拔的绝对值最小的那座
    然而xyz智商拙计,只带了一张相对海拔高度地图,于是要来求助你
    现在他知道这个斜坡有m种可能的斜率,请你对于每种斜率输出海拔最低的山峰的高度
    我们定义每两座山之间的水平距离都为1,第0座山所在的土地海拔高度为0

    输入格式:
    第一行两个数n,m
    第二行有n个数 表示每座山峰的高度
    接下来m行每行有一个数p,表示这个斜坡可能的斜率(可能小于0)

    输出格式:
    对于每个询问输出一行,表示最矮的山峰的海拔高度

    样例输入:
    3 1
    3 2 1
    10

    样例输出:
    13

    数据范围:
    30%的数据 n,m<=1000
    100%的数据 n,m<=300000,max(|h[i]|)<10^12,max(|h[i]+i*p|)<10^18,

    时间限制:
    1s
    空间限制:
    64MB

    题解

    (f(k)=max{h_i+icdot k})
    这个显然可以斜率优化。
    (h_i=-kcdot i+f(k))
    要找最小值,维护下凸包即可。用二分实现查询。

    时间复杂度(O(n+mlog n))

    #include<bits/stdc++.h>
    #define co const
    #define il inline
    template<class T> T read(){
    	T x=0,w=1;char c=getchar();
    	for(;!isdigit(c);c=getchar())if(c=='-') w=-w;
    	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    	return x*w;
    }
    template<class T>il T read(T&x){
    	return x=read<T>();
    }
    using namespace std;
    #define int long long
    
    struct Vector {int x,y;};
    il Vector operator+(co Vector&a,co Vector&b){
    	return (Vector){a.x+b.x,a.y+b.y};
    }
    il Vector operator-(co Vector&a,co Vector&b){
    	return (Vector){a.x-b.x,a.y-b.y};
    }
    il int cross(co Vector&a,co Vector&b){
    	return a.x*b.y-a.y*b.x;
    }
    
    co int N=300000+2;
    int n,m;
    Vector p[N],ch[N];
    signed main(){
    	read(n),read(m);
    	for(int i=1;i<=n;++i) p[i].x=i,read(p[i].y);
    	int num=0;
    	for(int i=1;i<=n;++i){
    		while(num>=2&&cross(ch[num]-ch[num-1],p[i]-ch[num-1])<=0) --num;
    		ch[++num]=p[i];
    	}
    	while(m--){
    		int k=read<int>();
    		int l=1,r=num;
    		while(l<r){
    			int mid=(l+r)>>1;
    			if(-k*(ch[mid+1].x-ch[mid].x)>ch[mid+1].y-ch[mid].y) l=mid+1;
    			else r=mid;
    		}
    		printf("%lld
    ",ch[l].y+k*ch[l].x);
    	}
    	return 0;
    }
    

    ctps

    4维空间中有1个点集A,|A|=n,用(a,b,c,d)表示每个点。
    共有m个询问,每次询问输入一个点(a,b,c,d),求最大的S,其中S={p|p∈A且ap<=a,bp<=b,cp<=c,dp<=d},输出|S|

    输入格式:
    第一行n
    接下来n行有n个4维点对
    第n+2行有一个数m
    再接下来m行每行有一个四维点对,表示每个询问

    输出格式:
    对于每个询问输出一个数

    样例输入:
    1
    0 0 0 0
    2
    1 1 1 1.0
    1 1 1 -1

    样例输出:
    1
    0

    数据范围:
    n,m<=30000

    时间限制:
    2s
    空间限制:
    256MB

    题解

    四位偏序模板题。

    考场上时间分治套时间分治套树状数组不知道哪里写挂了。

    我想把离散化去掉,于是重构写了时间分治套时间分治套时间分治。

    然后发现初始排序的时候要写stable_sort。分析如下:
    因为题目中要求的是≤,所以CDQ的时候尽量先修改。然后外层也要这样保证,所以询问放到修改之后,使用stable_sort以维持这种尽量关系。

    时间复杂度(O(n log^3 n))。分块bitset留坑,据出题人说他没有卡这种算法所以它跑得快。

    #include<bits/stdc++.h>
    #define co const
    #define il inline
    using namespace std;
    
    co int N=60000+1;
    int n,m,ans[N];
    
    struct node2{double d;int id;}p2[N],q2[N];
    void solve2(int l,int r){
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	solve2(l,mid),solve2(mid+1,r);
    	int ql=l,qr=mid+1,cnt=0;
    	for(int i=l;i<=r;++i){
    		if(ql<=mid&&(qr>r||p2[ql].d<=p2[qr].d)){
    			q2[i]=p2[ql++];
    			if(!q2[i].id) ++cnt;
    		}
    		else{
    			q2[i]=p2[qr++];
    			if(q2[i].id>0) ans[q2[i].id]+=cnt;
    		}
    	}
    	copy(q2+l,q2+r+1,p2+l);
    }
    
    struct node1{double c,d;int id;}p1[N],q1[N];
    void solve1(int l,int r){
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	solve1(l,mid),solve1(mid+1,r);
    	int ql=l,qr=mid+1;
    	for(int i=l;i<=r;++i){
    		if(ql<=mid&&(qr>r||p1[ql].c<=p1[qr].c)){
    			q1[i]=p1[ql++];
    			p2[i].d=q1[i].d,p2[i].id=!q1[i].id?0:-1;
    		}
    		else{
    			q1[i]=p1[qr++];
    			p2[i].d=q1[i].d,p2[i].id=q1[i].id>0?q1[i].id:-1;
    		}
    	}
    	solve2(l,r);
    	copy(q1+l,q1+r+1,p1+l);
    }
    
    struct node{double a,b,c,d;int id;}p[N],q[N];
    void solve(int l,int r){
    	if(l==r) return;
    	int mid=(l+r)>>1;
    	solve(l,mid),solve(mid+1,r);
    	int ql=l,qr=mid+1;
    	for(int i=l;i<=r;++i){
    		if(ql<=mid&&(qr>r||p[ql].b<=p[qr].b)){
    			q[i]=p[ql++];
    			p1[i].c=q[i].c,p1[i].d=q[i].d,p1[i].id=!q[i].id?0:-1;
    		}
    		else{
    			q[i]=p[qr++];
    			p1[i].c=q[i].c,p1[i].d=q[i].d,p1[i].id=q[i].id>0?q[i].id:-1;
    		}
    	}
    	solve1(l,r);
    	copy(q+l,q+r+1,p+l);
    }
    
    il bool operator<(co node&a,co node&b){
    	return a.a<b.a;
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;++i)
    		scanf("%lf%lf%lf%lf",&p[i].a,&p[i].b,&p[i].c,&p[i].d);
    	scanf("%d",&m);
    	for(int i=1;i<=m;++i){
    		scanf("%lf%lf%lf%lf",&p[n+i].a,&p[n+i].b,&p[n+i].c,&p[n+i].d),p[n+i].id=i;
    	}
    	stable_sort(p+1,p+n+m+1); // edit 1:stable
    	solve(1,n+m);
    	for(int i=1;i<=m;++i) printf("%d
    ",ans[i]);
    	return 0;
    }
    

    不得不说,学军中学某些数据很强。

    直线和点

    平面的n条直线将平面分割成了若干区域,给出m个点,求每个点所在区域的面积。
    为了防止出现面积无穷大的情况,有额外的四条直线框定了平面区域的大小,分别是x=L y=L x=-L y=-L。其中L是给定的正实数,所有的点都在这个框定的区域内。
    另外为了防止精度问题,任意一个点到任意一条直线的距离>10^-7。

    输入格式:
    第一行两个正整数和一个正实数,n,m,L,意义如上所述。
    第2~n-1行每行三个实数A,B,C表示直线的方程为Ax+By+C=0。
    第n+2~n+m+1行每行两个实数x,y表示点的坐标。

    输出格式:
    按输入的顺序输出每个点所在的区域面积,每个一行,保留2位小数。

    样例输入:
    2 4 3
    1 1 -1
    -1 1 -1
    0 2
    -2 1
    2 1
    0 0

    样例输出:
    4.00
    8.50
    8.50
    15.00

    数据范围:
    对于20%的数据,n,m<=10。
    对于40%的数据,n,m<=300。
    对于100%的数据,n<=500,m<=100000。
    对于100%的数据,输入数据的绝对值<=10^7且最多保留2位小数。

    时间限制:
    2S
    空间限制:
    512M

    题解

    刘老爷每次暴力半平面交有40分。

    这道题先要求出PSLG,Planar Straight Line Graph,然后用离线+扫描线来判断每个点所处的凸多边形。

    时间复杂度(O(n^2+mn)),但我觉得这题没必要会写。

    讲题人疯狂暗示多边形下海。

  • 相关阅读:
    Bellman-Ford算法
    POJ3468--A Simple Problem with Integers(Splay Tree)
    【组队训练】2014鞍山区域赛
    Educational Codeforces Round 85 (Rated for Div. 2)
    HDU6061 RXD and functions【NTT】
    HDU6434 Count【欧拉函数 线性筛】
    2017-2018 ACM-ICPC German Collegiate Programming Contest (GCPC 2017)(9/11)
    2015 German Collegiate Programming Contest (GCPC 15) + POI 10-T3(12/13)
    CodeCraft-20 (Div. 2)
    图论题集
  • 原文地址:https://www.cnblogs.com/autoint/p/test20190805.html
Copyright © 2011-2022 走看看