【SCOI2016】Day2初略题解

【T1 妖怪】

        \ \ \ \ \ \,       对于一个妖怪的两个属性,为了方便我们把它定义为 x x x y y y,而要求的一个妖怪的战斗力应该为:

( b a + 1 ) x + ( a b + 1 ) y (\frac{b}{a}+1)x+(\frac{a}{b}+1)y (ab+1)x+(ba+1)y

        \ \ \ \ \ \,       既:

b a x + a b y + x + y \frac{b}{a}x+\frac{a}{b}y+x+y abx+bay+x+y

        \ \ \ \ \ \,       由于 x x x y y y 已经确定,所以我们需要找的是 b a x + a b y \frac{b}{a}x+\frac{a}{b}y abx+bay 最大的最小。

        \ \ \ \ \ \,      容易得到这是个对勾函数,对于一个怪物,当 b a = y x \frac{b}{a}=\sqrt{\frac{y}{x}} ab=xy 时,战斗力最小。

        \ \ \ \ \ \,      所以我们以 x x x y y y 为横纵坐标做个上凸壳,那么答案就一定是在凸壳上面,就会存在下面两种情况:

  • 在点上: b a = y x \frac{b}{a}=\sqrt{\frac{y}{x}} ab=xy
  • 在边上:需要满足:
    ( b a + 1 ) x 1 + ( a b + 1 ) y 1 = ( b a + 1 ) x 2 + ( a b + 1 ) y 2 (\frac{b}{a}+1)x_1+(\frac{a}{b}+1)y_1=(\frac{b}{a}+1)x_2+(\frac{a}{b}+1)y_2 (ab+1)x1+(ba+1)y1=(ab+1)x2+(ba+1)y2
    解得: b a = y 1 − y 2 x 2 − x 1 \frac{b}{a}=\frac{y_1-y_2}{x_2-x_1} ab=x2x1y1y2

        \ \ \ \ \ \,      就这样扫一遍过去就行了,复杂度 O ( n log ⁡ n ) O(n \log n) O(nlogn)

#include<queue>
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int inf=0x7fffffff;
const int eps=1e-10;
const double pi=acos(-1.0);
inline int read(){
	int x=0,p=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+(c&15);c=getchar();}
	return x*p;
}
const int N=1e6+20;
int n,m;
struct Point{long long x,y;}p[N],f[N];
inline Point operator +(const Point &a,const Point &b){return (Point){a.x+b.x,a.y+b.y};}
inline Point operator -(const Point &a,const Point &b){return (Point){a.x-b.x,a.y-b.y};}
inline bool operator <(const Point &a,const Point &b){return a.x==b.x?a.y<b.y:a.x<b.x;}
inline long long Cross(const Point &a,const Point &b){return a.x*b.y-a.y*b.x;}
int Solve(Point *P,int n,Point *F){
	sort(P+1,P+n+1);int top=0;
	for(register int i=1;i<=n;++i){
		for(;top>1&&Cross(F[top]-F[top-1],P[i]-F[top-1])>=0;top--);
    	F[++top]=P[i];
  	}
  	return top;
}
inline double solve(const Point &a,double k){return k<=0?inf:(double)a.x+a.y+k*a.x+a.y/k;}
inline double Getval_point(const Point &a){return sqrt((double)a.y/a.x);}
inline double Getval_line(const Point &a,const Point &b){return a.x==b.x?-inf:((double)(a.y-b.y)/(double)(b.x-a.x));}
int main(){
	freopen("monster.in","r",stdin);
	freopen("monster.out","w",stdout);
	n=read();
	for(register int i=1;i<=n;++i)p[i].x=1ll*read(),p[i].y=1ll*read();
	m=Solve(p,n,f);
	if(m<2){
		printf("%.4lf",solve(f[1],Getval_point(f[1])));
	}
	else{
		double k1,k2,k3,ans=inf;
		k1=Getval_point(f[1]),k2=Getval_line(f[1],f[2]);
		if(k1<=k2)ans=min(ans,solve(f[1],k1));
		k1=Getval_point(f[m]),k2=Getval_line(f[m-1],f[m]);
		if(k1>=k2)ans=min(ans,solve(f[m],k1));
    	ans=min(ans,solve(f[m],k2));
    	for(register int i=2;i<m;++i){
      		k1=Getval_line(f[i-1],f[i]);
      		k2=Getval_line(f[i],f[i+1]);
      		k3=Getval_point(f[i]);
      		ans=min(ans,solve(f[i],k1));
      		if(k1<=k3&&k3<=k2)
      		ans=min(ans,solve(f[i],k3));
    	}
  		printf("%.4lf\n",ans);
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}


【T2 美味】

      &ThinSpace; \ \ \ \ \ \,      又是异或最大呢,不是线性基就是贪心了,day1才搞了线性基,可以排除,我们看看怎么贪心。

      &ThinSpace; \ \ \ \ \ \,      首先可以看到他有一个取值范围的限制,我们可以用到可持久化数据结构维护。

      &ThinSpace; \ \ \ \ \ \,      然后我们可以贪心地想,从高位到低为维护 a i a_i ai 的存在性。这个可持久化数据结构需要满足下面的操作:

  • 插入一个数;
  • 删除一个数;
  • 统计某个取值范围的数数量是多少。

      &ThinSpace; \ \ \ \ \ \,      我最后选择了权值主席树。

      &ThinSpace; \ \ \ \ \ \,      现在对于每一次询问,我们贪心一下,从高位到低位枚举,如果 b b b这一位为 1 1 1,我们就找 0 0 0 ,反之找 1 1 1

      &ThinSpace; \ \ \ \ \ \,      怎么找呢?我们令当前找到第 i i i位, a n s ans ans 等于当前最优的 a i + x a_i+x ai+x,那么我们就找当前 [ l , r ] [l,r] [l,r] 范围内,是否存在有数次在区间( 1 / 0 1/0 1/0为当前要找的数):

[ a n s + ( 1 / 0 &lt; &lt; i ) − x , a n s + ( 1 / 0 &lt; &lt; i ) − x + ( 1 &lt; &lt; i ) − 1 ] [ans+(1/0&lt;&lt;i)-x,ans+(1/0&lt;&lt;i)-x+(1&lt;&lt;i)-1] [ans+(1/0<<i)x,ans+(1/0<<i)x+(1<<i)1]

      &ThinSpace; \ \ \ \ \ \,      存在的话就更新 a n s ans ans a n s + ( 1 / 0 &lt; &lt; i ) ans+(1/0&lt;&lt;i) ans+(1/0<<i),不然退而求其次,取 a n s + ( 0 / 1 &lt; &lt; i ) ans+(0/1&lt;&lt;i) ans+(0/1<<i)

      &ThinSpace; \ \ \ \ \ \,      这样我们可以保证在完成贪心,取到第0位之时, a n s ans ans 等于最优的 a i + x a_i+x ai+x。(并不关心是哪个 a i a_i ai,反正是拼出来了。

      &ThinSpace; \ \ \ \ \ \,      复杂度 O ( n log ⁡ a m a x + m log ⁡ 2 a m a x ) O(n \log a_{max}+m\log^2 a_{max}) O(nlogamax+mlog2amax)

#include<queue>
#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
inline int read(){
	int x=0,p=1;char c=getchar();
	while(c<'0'||c>'9'){if(c=='-') p=-1;c=getchar();}
	while(c<='9'&&c>='0'){x=(x<<1)+(x<<3)+(c&15);c=getchar();}
	return x*p;
}
const int N=5e5+5;
int a[N],root[N];
int n,m,nn;
struct CM_Tree{
	#define lson l,mid,ls[rt]
	#define rson mid+1,r,rs[rt]
	int ls[N*20],rs[N*20],sum[N*20],size;
	int copy(int rt){
		ls[++size]=ls[rt];
		rs[size]=rs[rt];
		sum[size]=sum[rt];
		return size;
	}
	void update(int id,int l,int r,int &rt){
    	rt=copy(rt);sum[rt]++;
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(id<=mid)update(id,lson);
    	else update(id,rson);
	}
	int query(int L,int R,int l,int r,int rt,int rt2){
    if(L<=l&&r<=R)return sum[rt2]-sum[rt];
    	int mid=(l+r)>>1,ret=0;
    	if(L<=mid)ret+=query(L,R,lson,ls[rt2]);
    	if(mid<R)ret+=query(L,R,rson,rs[rt2]);
    	return ret;
	}
}tree;
bool check(int i,int j,int L,int R){
	L=max(0,L);R=min(R,nn);
	if(L>R)return 0;
	return tree.query(L,R,0,nn,root[i],root[j])>0;
}
#define getbit(a,i) ((a>>i)&1)
int main(){
	freopen("food.in","r",stdin);
	freopen("food.out","w",stdout);
	n=read();m=read();
	for(register int i=1;i<=n;++i)a[i]=read(),nn=max(nn,a[i]);
  	for(register int i=1;i<=n;++i)root[i]=root[i-1],tree.update(a[i],0,nn,root[i]);
  	for(register int i=1;i<=m;++i){
    	int b=read(),x=read(),l=read(),r=read(),ans=0;
    	for(register int i=17,ls;i>=0;--i){
    		if(!getbit(b,i))ls=ans+(1<<i)-x;
    		else ls=ans-x;
      		if(check(l-1,r,ls,ls+(1<<i)-1))ans=ls+x;
      		else ans+=getbit(b,i)<<i;
    	}
    	printf("%d\n",ans^b);
  	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}


【T3 围棋】

      &ThinSpace; \ \ \ \ \ \,      插头dp是不会做插头dp的,这辈子不可能做插头dp的。写起来又怪麻烦,就是打打傻逼暴力,才能骗得了分这样子。

      &ThinSpace; \ \ \ \ \ \,      (逃

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值