test20190729 夏令营NOIP训练14
40+100+0=140.
基因光线
黑大帅统治古古怪界后,一直在玩一种很奇葩的游戏。在一个二维平面上,他先复制了n个小A,把他们放在不同的位置,然后射出一条ax+by+c=0的基因光线,宽度为d,即离这条直线的距离不大于d的小A会被射中。当然,某些悲剧的小A就会被射中,并变成黑小A。当然,这不是重点。玩了很久后,黑大帅猛然发现,自己竟然一次都没有射中小A。黑大帅怒了,于是他开启了作弊模式,将c改成自己想要的任意数值。现在,黑大帅想知道,在开启了作弊模式后,他射出一道基因光线最多能击中几个小A。
输入格式:
第一行五个数字a,b,d,n,接下来n行每行两个数字x,y表示这个小A的坐标。
输出格式:
一行一个数字表示最多能击中几个小A。
样例输入:
1 -1 0.707106782 5
0 0
1 0
0 1
2 0
2 1
样例输出:
4
数据范围:
50%的数据满足a=0;
100%的数据满足n<=100000,其余所有数值均为绝对值不大于1000的实数。
时间限制:
1s
空间限制:
64M
写了一个旋转扫描,炸了精度,WA成40.
后来翻刘老爷的代码知道,可以直接计算三角函数值而不必先求角度再代函数。
好朋友
noip2011就要来了,W校的同学们不仅看重这次比赛,更看重noip2011和谁住在同一个房间。同学之间的关系好坏可以用一个亲密值表示,亲密值越大,两个同学关系越好。小A作为W校信息组的组长,自然想要让同学们在比赛前能好好休息,放松心情,让同学们在赛场上能够超常发挥。他现在知道自己预订的房间都是双人间,且知道这n个同学之间的关系。n个同学的关系可以用一个n条双向边的连通图来描述,即某个同学只愿意和与他有边相连的同学住同一个房间,边权即为两个同学的亲密值。数据保证没有重边、自环。现在小A想知道在让所有同学的要求满足的情况下,亲密值最低的一对同学亲密值最高是多少。
输入格式:
第一行一个正整数n,下面n行每行三个数u,v,w,表示u到v有一条边权为w的双向边。
输出格式:
假如无论如何都无法满足所有同学的要求,输出”no answer”,否则输出亲密值最低的一对同学的最高亲密值。
样例输入:
4
1 2 3
2 3 10
3 4 3
1 4 1
样例输出:
3
数据范围:
50%的数据满足n<=20;
80%的数据满足n<=1000;
100%的数据满足n<=100000,-109<=w<=109
时间限制:
1S
空间限制:
64M
题解
先二分答案转化为判定问题,然后考虑怎么做。
其实就是一个剥叶子的过程,类似拓扑排序。但要注意因为是基环树最后可能剩下一个环,所以还要判断环上点数的奇偶性。\(O(n\log n)\)
但是发现大家都是二分答案+二分图匹配,我不知道这\(O(n^2 \log n)\)是怎么过的。
少数人写的\(O(n)\)的剥叶子,考虑什么时候会有多解的情况,只有在环上的时候。而这个环的方案数只有2……
砍树(2)
小A是小B家的园丁。小B的家里有n棵树,第i棵树的横坐标为i。一天,小B交给小A一个任务,让他降低自己家中的某些树木的高度。这个任务对小A来说十分简单,因为他有一把极其锋利的斧头和一门独门砍树秘籍,能够轻易地砍断任何参天大树。小A的砍树方法有3种,都是沿着一条y=kx+b的直线砍一段区间的树,相同的方法k值相同。只用了一个下午,小A就完成了小B的任务。第二天,小B来视察小A的任务完成情况。小B想知道小A是否真的用心砍树,于是提出了q个询问,每次询问一段区间中最低的树的高度。小A当然是不会记住树木的砍伐情况的,他只知道自己按什么顺序,使用了什么方法,砍了哪个连续区间的树,而且区间都是互不包含的。现在小A想请你帮帮他,回答小B的询问。
输入格式:
第一行三个整数k1,k2,k3表示小A三种砍树方法的斜率值;
第二行一个数n,表示一共有n棵树;
第三行n个数hi,分别表示n棵树的高度;
第四行一个数m,表示小A一共进行了m次操作;
接下来m行,每行四个数L,R,p,b,表示用第p种方法,即用y=kp+b的直线砍[L,R]区间的树;
接下来一行一个数q,表示小B的询问数;
接下来q行,每行两个数L,R,表示询问[L,R]区间中最低的树的高度。
输出格式:
一共q行,每行一个数h表示对应的回答。
样例输入:
1 0 -1
4
10 30 20 1
2
3 4 2 5
1 3 3 10
2
1 2
2 3
样例输出:
8
5
数据范围:
n<=1000000,m<=500000
时间限制:
3s
空间限制:
64M
提示:
如下图,红色即为树的剩余部分。
题解
暴力有60分,这边的人很大方。
考场上感觉是一个维护下凸包的问题,然后觉得这扫描线实在难写,而我只剩下40分钟了,所以打了一个暴力。
然后翻别人的代码,发现因为是先改后查,就对三个斜率分别维护纵截距最小值,然后全局统计一下就行了。线段树即可解决,感觉自己弱智++。
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,r,l) for(int i=(r);i>=(l);--i)
using namespace std;
int k[3],val[2100005],b[2100005][3],h[1100005],l[2100005],r[2100005],n,m,q;
const int INF=100000000;
int build(int ll,int rr,int no){
int mid=(ll+rr)>>1;l[no]=ll;r[no]=rr;
b[no][0]=b[no][1]=b[no][2]=INF;
if(ll==rr){return val[no]=h[ll];}
int lc=no<<1,rc=lc+1;
return val[no]=min(build(ll,mid,lc),build(mid+1,rr,rc));
}
void update(int no,int x,int y,int p,int bb){
if(l[no]==x&&r[no]==y){b[no][p]=min(b[no][p],bb);return;}
int mid=(l[no]+r[no]) >> 1,lc=no*2,rc=lc+1;
if(x>mid){update(rc,x,y,p,bb);return;}
if(y<=mid){update(lc,x,y,p,bb);return;}
update(lc,x,mid,p,bb);update(rc,mid+1,y,p,bb);
return;
}
void dfs(int no){
int lc=no*2,rc=lc+1;
if(l[no]!=r[no]){
rep(i,0,2){
int wa=b[no][i];
b[lc][i]=min(b[lc][i],wa);
b[rc][i]=min(b[rc][i],wa);
}
dfs(lc);dfs(rc);
val[no]=min(val[lc],val[no]);
val[no]=min(val[rc],val[no]);
}
else{
rep(i,0,2){
int wa=b[no][i];
if(wa!=INF) val[no]=min(val[no],k[i]*r[no]+wa);
}
}
}
int query(int no,int x,int y){
if(l[no]==x&&r[no]==y) return val[no];
int mid=(l[no]+r[no])>>1;int lc=no*2,rc=lc+1;
if(y<=mid) return query(lc,x,y);
if(x>mid) return query(rc,x,y);
return min(query(lc,x,mid),query(rc,mid+1,y));
}
int main()
{
scanf("%d%d%d",&k[0],&k[1],&k[2]);
scanf("%d",&n);
rep(i,1,n) scanf("%d",&h[i]);
build(1,n,1);
scanf("%d",&m);
while(m--){
int l,r,p,b;
scanf("%d%d%d%d",&l,&r,&p,&b);
update(1,l,r,p-1,b);
}
scanf("%d",&q);
dfs(1);
while(q--){
int l,r;
scanf("%d%d",&l,&r);
printf("%d\n",query(1,l,r));
}
}