noip模拟赛34 Merchant Equation Rectangle

Merchant

考场思路:

考场上想到了二分,但是并不知道nth_element这种高端的东西,于是用了优先队列。但是由于忘记了清空队列,所以挂了。

正解:

由题意可知,每一个物品的集合必定是一个一次函数。随着时间的增加,最大值是先降后增的。在下降区段,必定是没有零点优的,所以只需要先特判零点,然后对于以后的时间进行二分,使用nth_element,O(N)求出最小的n-m个值,选出剩下的至多m个值,判断是否符合条件,变更l,r。

tip:nth_element(a+1,a+m+1,a+n+1);能够在O(n)时间内处理出最小的m个值(是无序的)。

代码实现
#include<bits/stdc++.h>
#define lt long long
#define int long long
using namespace std;

const int N=10000050;
int n,m;
lt s;
lt k[N],b[N],a[N];
lt ans,ens;
signed main(){
	scanf("%lld%lld%lld",&n,&m,&s);
	for(int i=1;i<=n;++i){
		scanf("%lld%lld",&k[i],&b[i]);
		a[i]=b[i];
	}
	sort(a+1,a+1+n);
	for(int i=n;i>=n-m+1;i--){
		ans+=a[i];
		if(ans>=s){
			printf("0\n");
			return 0;
		}
	}
	lt l=0,r=10000000005;
	while(1<r-l){
		lt mid=(r+l)>>1;
		for(int i=1;i<=n;++i){
			a[i]=k[i]*mid+b[i];
		}
		nth_element(a+1,a+n-m+1,a+n+1);
		bool b=0;
		ans=0;
		for(int i=n;i>=n-m+1;--i){
			if(a[i]>0)ans+=a[i];
			if(ans>=s){
				b=1;
				break;
			}
		}
		if(b){
			r=mid;
		}
		else{
			l=mid;
		}
//		printf("%lld %lld %lld\n",mid,ans,s);
	}
	cout<<r<<endl;
	return 0;
}

Equation

考场思路:

考场上想到了正解,然鹅由于失智行为,只得了3分(不删freopen都能得这么多分)

正解:

从根节点向下按照式子推,可以发现,每一个数都可以表示成 \(x_{i} =k+x_{1}\)\(x_{i} =k-x_{1}\) 的形式,此时对于询问我们便可以轻松的回答询问了。对于修改操作我们发现,深度奇偶性相同的两个点,修改其中一个点,对于另一个的贡献是相同的;而对于相反的点,修改其中一个点,对于另一个的贡献是相反的。知道了这一点我们就可以建出线段树(用树状数组更快,线段树要大力卡常)去维护修改值,询问时对于奇数点与偶数点分别处理就好了。

代码实现
#include<bits/stdc++.h>
#define lt long long
using namespace std;

const int N=1000050;
int n,q;
int head[N],tot;
int dep[N],fa[N],id[N],rk[N],idnt,size[N];
lt t[N*4],val[N],yb[N];

struct edge{
	int nxt,to,dis;
}e[N*2];

inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    while(ch<‘0‘||ch>‘9‘){
        if(ch==‘-‘)
            f=-1;
        ch=getchar();
    }
    while(ch>=‘0‘&&ch<=‘9‘){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*f;
}


void ade(int x,int y,int z){
	e[++tot].nxt=head[x];
	e[tot].to=y;
	e[tot].dis=z;
	head[x]=tot;
}

void dfs1(int u){
	id[u]=++idnt;
	rk[idnt]=u;
	size[u]=1;
	for(int i=head[u];i;i=e[i].nxt){
		int v=e[i].to;
		dep[v]=dep[u]+1;
		val[v]=e[i].dis-val[u];
		dfs1(v);
		size[u]+=size[v];
	}
}
inline void pushdown(int u){
	if(!t[u]) return;
	t[u<<1]+=t[u];
	t[u<<1|1]+=t[u];
	t[u]=0;
}

void edit(int u,int l,int r,int ll,int rr,lt x){
	if(l>rr||r<ll){
		return;
	}
	if(l>=ll&&r<=rr){
		t[u]+=x;
		return;
	}
	pushdown(u);
	register int mid=(l+r)>>1;
	edit(u<<1,l,mid,ll,rr,x);
	edit(u<<1|1,mid+1,r,ll,rr,x);
}

int ask(int u,int l,int r,int x){
	if(l==r){
		return t[u];
	}
	pushdown(u);
	register int mid=(l+r)>>1,ans;
	if(x<=mid){
		ans=ask(u<<1,l,mid,x);
	}
	else{
		ans=ask(u<<1|1,mid+1,r,x);
	}
	return ans;
}

void que(int x,int y,lt z){
	if((dep[x]&1)==(dep[y]&1)){
		if(!(dep[x]&1)){
			lt anx,any,cnx,cny,cx;
			anx=ask(1,1,n,id[x]);
			any=ask(1,1,n,id[y]);
			cnx=anx+val[x];
			cny=any+val[y];
			cx=cnx+cny-z;
			if(cx&1){
				printf("none\n");
				return;
			}
			else{
				cx/=2;
				printf("%lld\n",cx);
			}
		}
		else{
			lt cnx,cny,cx;
			cnx=ask(1,1,n,id[x]);
			cny=ask(1,1,n,id[y]);
			cnx=val[x]-cnx;
			cny=val[y]-cny;
			cx=z-cnx-cny;
			if(cx&1){
				printf("none\n");
				return;
			}
			else{
				cx/=2;
				printf("%lld\n",cx);
			}
		}
	}
	else{
		if(dep[x]&1){
			lt cnx,cny;
			cnx=ask(1,1,n,id[x]);
			cny=ask(1,1,n,id[y]);
			cnx=val[x]-cnx;
			cny+=val[y];
			if(cnx+cny==z){
				printf("inf\n");
			}
			else{
				printf("none\n");
			}
		}
		else{
			swap(x,y);
			lt cnx,cny;
			cnx=ask(1,1,n,id[x]);
			cny=ask(1,1,n,id[y]);
			cnx=val[x]-cnx;
			cny+=val[y];
//			printf("%d %d %d %d %d %d",x,y,anx,cnx,any,cny);
			if(cnx+cny==z){
				printf("inf\n");
			}
			else{
				printf("none\n");
			}
		}
	}
}

int main(){
//	freopen("shuju.in","r",stdin);
//	freopen("my.out","w",stdout);
	scanf("%d%d",&n,&q);
	int fc,wc;
	for(register int i=2;i<=n;i++){
		fc=rd(),wc=rd();
		fa[i]=fc;
		yb[i]=wc;
		ade(fc,i,wc);
	}
	dep[1]=1;
	dfs1(1);
	int tp,uc,vc;
	lt sc,we;
	for(register int i=1;i<=q;++i){
		tp=rd();
		if(tp==1){
			uc=rd(),vc=rd(),sc=rd();
			que(uc,vc,sc);
		}
		else{
			uc=rd(),we=rd();
			if(!(dep[uc]&1)){
				edit(1,1,n,id[uc],id[uc]+size[uc]-1,we-yb[uc]);
				yb[uc]=we;
			}
			else{
				edit(1,1,n,id[uc],id[uc]+size[uc]-1,yb[uc]-we);
				yb[uc]=we;
			}
		}
	}
	return 0;
}
## Rectangle ####考场思路: 考场没思路……

正解:

很是难写的一道题。
首先枚举矩形的右边界,对于每一个有边界,从右往左枚举左边界
noip模拟赛34 Merchant Equation Rectangle
考虑左右边界在A,B之间的矩形,都可以以A到B为长,对于在蓝色区间的C点,和在橙色区间的D点,若两者和A,B构成点集,则上边界为C点,下边界为D点,左边界为B,右边界为A。每这样的两对点都能对答案产生贡献,于是得出以下式子
\(\displaystyle\sum_{i=1}^{mn}\displaystyle\sum_{j=mx}^{inf}(j-i)\)
将i从里面提出来,定义size[A]为从零到A的节点数量,定义sum[A]为从零到A的节点的纵坐标总和。
每一个C节点都有size[A]个贡献,减去的D节点的和为sum[A]
\(\displaystyle\sum_{i=mx}^{inf}i*size[A]-sum[A]\)
再将i表示出来
\(sum[i]*size[j]-sum[j]*size[i]\)
如果再l与r上有多个点时
noip模拟赛34 Merchant Equation Rectangle
对于绿色部分显然不能用B和A时维护,否则会有重复,所以在B和A时,只能维护蓝色区间,要在C和A时,再去维护黄色区间。
对于sum和size使用树状数组维护与查询(每次移动右边界时,清空树状数组)

代码实现
#include<bits/stdc++.h>
#define lt long long
using namespace std;

const int N=10050,mod=1e9+7;
int n;
int x[N],y[N];
vector<int> mc[3000];
int xmx,ymx;
int size[3000],sum[3000];
bool vis[3000][3000];
lt ens,anx,any;

int low(int x){
	return x&-x;
}

void add(int x,int y){
	x++;
	for(int i=x;i<=ymx+1;i+=low(i)){
		size[i]+=1;
		sum[i]+=y;
	}
}

void ask(int x,int y){
	y++;
	lt ana=0,anb=0,bna=0,bnb=0;
	for(int i=x;i;i-=low(i)){
		ana+=size[i];
		anb+=sum[i];
	}
	for(int i=y;i;i-=low(i)){
		bna+=size[i];
		bnb+=sum[i];
	}
//	printf("[%d %d %d %d]\n",ana,anb,bna,bnb);
	anx=bna-ana;any=bnb-anb;
//	if(anx<0) anx=0;
//	if(any<0) any=0;
}

int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i){
		scanf("%d%d",&x[i],&y[i]);
		xmx=max(xmx,x[i]);
		ymx=max(ymx,y[i]);
		mc[x[i]].push_back(y[i]);
	}
	for(int i=1;i<=xmx;++i){
		sort(mc[i].begin(),mc[i].end());
		mc[i].push_back(ymx+1);
	}
	for(int i=1;i<=xmx;++i){
//		cout<<endl<<i<<" rk "<<ens<<endl;
		memset(size,0,sizeof(size));
		memset(sum,0,sizeof(sum));
		
		int szi=mc[i].size()-1;
		if(!szi)continue;
		for(int k=0;k<szi;++k){
			if(!vis[i][mc[i][k]]){
				vis[i][mc[i][k]]=1;
				add(mc[i][k],mc[i][k]);
			}
		}
		for(int j=i-1;j>=1;--j){
			int szj=mc[j].size()-1;
			if(!szj) continue;
			for(int k=0;k<szj;++k){
				if(!vis[i][mc[j][k]]){
					vis[i][mc[j][k]]=1;
					add(mc[j][k],mc[j][k]);
				}
			}
			int tp1=0,tp2=0,up=max(mc[i][0],mc[j][0]);
			while(mc[i][tp1+1]<=up) tp1++;
			while(mc[j][tp2+1]<=up) tp2++;
			while(tp1<szi&&tp2<szj){
				int uup=min(mc[i][tp1+1],mc[j][tp2+1]);
				int down=min(mc[i][tp1],mc[j][tp2]);
				int aa,bb,cc,dd;
				ask(up,uup-1);
				aa=anx,bb=any;
				ask(1,down);
				cc=anx,dd=any;
				ens=(ens+((lt)(i-j)*(bb*cc-dd*aa)))%mod;
				up=uup;
				if(mc[i][tp1+1]<=up)tp1++;
				if(mc[j][tp2+1]<=up)tp2++;
//				printf("%d %d|",tp1,tp2);
			}
		}
	}
	printf("%lld\n",ens);
	return 0;
}

noip模拟赛34 Merchant Equation Rectangle

上一篇:【模板】快排模板


下一篇:1285:@变量赋值