Loading

noip模拟34

A.Merchant

我们可以发现在\(K\)全部大于\(0\)时,答案是单调的;
\(K\)全部小于\(0\)时,答案为\(0\)
然后我们考虑更一般的情况:
图像要么单调上升、要么单调下降、要么先降后升..

  • 单调上升:我们发现\(\Sigma_k\)大于\(0\)就可以单调上升.
  • 单调下降: 显然只有\(k\)全部都小于\(0\)时单调下降,所以此时可以选择等于\(0\)时最优.
  • 先降后升: 我们可以发现:存在\(k>0\)\(\Sigma_k<0\) , 但\(\Sigma_d>0\)此时我们会选择先判断 0 是够符合条件;如果不符合,那么我们就可以选择在\(k*t< \Sigma_{d*(k<0)}\)时不再选择这些价值小于\(0\)的物品,于是可以画出图像,发现其为先下降后上升..
    当先降后升时,我们可以在价值不满足时使指针向右移动,一定会找到满足条件的答案.

故二分可以解决..

A_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS
{
	#define ll long long int
	#define re register ll 
	#define lf double
	#define lb lower_bound 
	#define ub upper_bound 
	#define mp make_pair
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x);
	#define Copy(x,y) memset(y,x,sizeof x);
	inline ll read()
	{
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0;
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=1e6+51;
ll n,m,s;
ll a[N],b[N],w[N];
inline bool check(ll x){	
	ll res=0;
	for(re i=1;i<=n;i++) w[i]=a[i]*x+b[i];
	nth_element(w+1,w+n-m+1,w+n+1);
	for(re i=n;i>=n-m+1;i--){
		res+=(w[i]>0)*w[i];
		if(res>=s) return 1;
	}
	return res>=s;
}
signed main(){
	n=read(); m=read(); s=read();
	ll temp=0,flag=1;
	for(re i=1;i<=n;i++) a[i]=read(),b[i]=read(),temp+=b[i],flag&=(a[i]<0);
	if(flag or temp>s){ puts("0"); return 0; }
	ll le=0,ri=1e9+1,mid,res;
	while(le<=ri){	
		mid=(le+ri)>>1;
		if(check(mid)) res=mid,ri=mid-1;
		else le=mid+1;
	}
	printf("%lld",res);
	return 0;
}

B.Equation

一道简单的线段树,考场上因为忘了给子树传递信息挂没了..

B_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define p() puts("")
	#define ll long long int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memset(x,y,sizeof x)
	inline ll read() {
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=1e6+51;
const lf eps=1e-10;
ll m,n,ts,cnt;
ll w[N],head[N],dep[N],dfn[N],rk[N],siz[N],b[N];
lf a[15][15];
struct I { ll u,v,nxt; } e[N<<1|1];
struct II { ll lazy,sum; } tr[N*8];
inline void add(ll u,ll v){
	e[++ts].u=u;
	e[ts].v=v;
	e[ts].nxt=head[u];
	head[u]=ts;
}
inline void spread(ll x,ll l,ll r){
	if(tr[x].lazy){
		tr[x<<1].sum+=tr[x].lazy;
		tr[x<<1|1].sum+=tr[x].lazy;
		tr[x<<1].lazy+=tr[x].lazy;
		tr[x<<1|1].lazy+=tr[x].lazy;
		tr[x].lazy=0;
	}
	return ;
}
ll query(ll x,ll l,ll r,ll pos){
	if(l==r) return tr[x].sum;
	ll mid=(l+r)>>1;
	spread(x,l,r);
	if(pos<=mid) return query(x<<1,l,mid,pos);
	else return query(x<<1|1,mid+1,r,pos);
}
void update(ll x,ll l,ll r,ll ql,ll qr,ll val){
	if(l>=ql and r<=qr) {
		tr[x].sum+=val;
		tr[x].lazy+=val;
		return ;
	}
	ll mid=(l+r)>>1;
	spread(x,l,r);
	if(ql<=mid) update(x<<1,l,mid,ql,qr,val);
	if(qr>=mid+1) update(x<<1|1,mid+1,r,ql,qr,val);
	return ;
}
void dfs(ll now,ll val,ll depth){
	dfn[now]=++cnt; rk[cnt]=now;
	siz[now]=1;
	if(depth&1) b[now]=val-w[now]; // 奇数 为 -1
	else b[now]=val+w[now];
	dep[now]=depth;
	for(re i=head[now];i;i=e[i].nxt){
		dfs(e[i].v,b[now],depth+1);
		siz[now]+=siz[e[i].v];
	}
	return ;
}
void Guass(ll u,ll v,ll temp){
	if(u>v) swap(u,v);
	a[1][1]=1.0,a[1][2]=1.0,a[1][3]=temp*1.0;	
	b[u]=query(1,1,n,dfn[u]); b[v]=query(1,1,n,dfn[v]);
	if(dep[u]&1) a[2][1]=-1.0;
	else a[2][1]=1.0;
	if(dep[v]&1) a[2][2]=1.0;
	else a[2][2]=-1.0;
	a[2][3]=(b[u]-b[v])*1.0;
/*	for(re i=1;i<=2;i++){
		for(re j=1;j<=3;j++)
		printf("%.2lf ",a[i][j]);
		puts("");
	}puts("");
*/
			
	if(a[1][1]==a[2][1] and a[1][2]==a[2][2] and a[1][3]==a[2][3]){
		puts("inf"); return ;
	}
	if(a[1][1]==a[2][1] and a[1][2]==a[2][2] and a[1][3]!=a[2][3]){
		puts("none"); return ;
	}
	if(a[1][1]==-a[2][1] and a[1][2]==-a[2][2] and a[1][3]==-a[2][3]){
		puts("inf"); return ;
	}
	if(a[1][1]==-a[2][1] and a[1][2]==-a[2][2] and a[1][3]!=-a[2][3]){
		puts("none"); return ;
	}
	a[2][2]-=a[2][1]*a[1][2];
	a[2][3]-=a[2][1]*a[1][3];
	lf res=a[2][3]/a[2][2];
	if(dep[v]&1) res+=b[v];
	else res=b[v]-res;
	temp=(ll)res;
	if(res!=(ll)res) puts("none");
	else printf("%lld\n",temp);
	return ;
}
signed main(){
	n=read(); m=read();
	ll u,v,opt,temp;
	for(re i=2;i<=n;i++){
		v=read(),w[i]=read();
		add(v,i); // add(i,v);
	}
	dfs(1,0,1);
	for(re i=1;i<=n;i++){
		update(1,1,cnt,dfn[i],dfn[i],b[i]);
	}
	for(re i=1;i<=m;i++){
		opt=read();
		if(opt&1){
			u=read(),v=read();
			Guass(u,v,read());
		}
		else{
			u=read();
			if(dep[u]&1){
				update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,w[u]);
				w[u]=read();
				update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,-w[u]);
			}
			else{
				update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,-w[u]);
				w[u]=read();
				update(1,1,cnt,dfn[u],dfn[u]+siz[u]-1,w[u]);
			}
		}
	}
	return 0;
}

C.Rectangle

考场上想了很多:

  1. 考虑每个方块造成的贡献,但是转移复杂度过于巨大,且思维量和码量都很巨大,甚至还要使用容斥,于是果断放弃..
  2. 使用\(O(n^4)\)枚举每个矩形,然后在此基础上优化,使用线段树进行统计,但是并不知道如何才能使用数据结构节约复杂度..

正解是使用枚举左右两个边界:
我们从右往左枚举左边界,然后从左边界向右枚举右边界..
之所以这么做,是因为中间枚举到的点会对将来的统计造成贡献,因为也会被当作边界处理..
然后我们就得到了左边界\(L\)和右边界\(R\)..
于是答案即为\((R-L)*\Sigma_h\)..
考虑如何求出\(\Sigma_h\)..
我们选择使用树状数组,维护\(sum\)\(size\)即可..线段树常数较大,且许多\(log(M)\)皆为满,故适用树状数组..
我们从下往上分别统计矩形的上下边界,每统计完一段区间的答案,然后移动右边界,并使右边界的点都依附到左边界即可..

C_code
#include<bits/stdc++.h>
using namespace std;
namespace BSS {
	#define ll int 
	#define ull unsigend ll
	#define re register ll 
	#define lf double
	#define lbt(x) (x&(-x))
	#define mp(x,y) make_pair(x,y)
	#define lb lower_bound 
	#define ub upper_bound
	#define File(x,y) freopen(#x,"r",stdin),freopen(#y,"w",stdout)
	#define Fill(x,y) memset(x,y,sizeof x)
	#define Copy(x,y) memset(x,y,sizeof x)
	inline ll read() {
		ll ss=0; bool cit=1; char ch;
		while(!isdigit(ch=getchar())) if(ch=='-') cit=0; 
		while(isdigit(ch)) ss=(ss<<3)+(ss<<1)+(ch^48),ch=getchar();
		return cit?ss:-ss;
	}
} using namespace BSS;

const ll N=1e6+53,M=2501;
const ll mod=1e9+7;
ll m,n,ans;
ll cnt[M+1000],vis[M+1000];
ll pot[M+1000][M+1000];
inline ll mk(ll i,ll j){ return (i+j)%mod; }
inline ll des(ll i,ll j){ return (i+mod-j)%mod; }
struct I { ll sum,num,lazy; } tr[M*80];
struct II { 
	ll c[N+50],res;
	void update(ll x,ll val){
		while(x<=M){
			c[x]+=val;
			x+=lbt(x);
		}
	}
	ll query(ll x){
		res=0;
		while(x){
			res+=c[x];
			x-=lbt(x);
		}
		return res;
	}
}sum,siz;
signed main(){
	n=read();
	ll x,y,le=1e9,ri=0;;
	for(re i=1;i<=n;i++){
		x=read(); y=read();
		pot[x][++cnt[x]]=y;
		le=min(le,x); ri=max(ri,x);
	}

	for(re i=le;i<=ri;i++){
		pot[i][0]=0,pot[i][cnt[i]+1]=M;
		sort(pot[i]+1,pot[i]+2+cnt[i]);
	}
	for(re i=le;i<=ri;i++){
		if(!cnt[i]) continue;
		for(re j=1;j<M;j++) sum.c[j]=siz.c[j]=vis[j]=0;
		for(re j=1;j<=cnt[i];j++){
			if(!vis[pot[i][j]]){
			sum.update(pot[i][j],pot[i][j]),siz.update(pot[i][j],1);
			vis[pot[i][j]]=1; }
		}
		for(re j=i-1;j>=le;j--){
			if(!cnt[j]) continue;
			for(re k=1;k<=cnt[j];k++){
				if(!vis[pot[j][k]]) {
				sum.update(pot[j][k],pot[j][k]),siz.update(pot[j][k],1);
				vis[pot[j][k]]=1; }
			}
			ll p1=1,p2=1,st,en,lmt,ans1,ans2;
			en=max(pot[i][p1],pot[j][p2]);
			while(pot[i][p1+1]<=en) p1++;
			while(pot[j][p2+1]<=en) p2++;
			while(p1<=cnt[i] and p2<=cnt[j]){
				lmt=min(pot[i][p1+1],pot[j][p2+1]);
				st=min(pot[i][p1],pot[j][p2]);
				ans1=(des(sum.query(lmt-1),sum.query(en-1))*1ll*siz.query(st))%mod,
				ans1=(1ll*ans1*des(i,j))%mod,
				ans2=des(siz.query(lmt-1),siz.query(en-1))*1ll*sum.query(st)%mod,
				ans2=(1ll*ans2*des(i,j))%mod,
				ans=mk(ans,des(ans1,ans2)), en=lmt;
				while(pot[i][p1+1]<=en and pot[i][p1+1]) p1++;
				while(pot[j][p2+1]<=en and pot[j][p2+1]) p2++;
			}
		}
	}
	printf("%d",ans%mod);
	return 0;
}	
posted @ 2021-08-09 20:25  AaMuXiiiiii  阅读(53)  评论(1编辑  收藏  举报