2019/11/11 校内模拟

敲日期的时候才发现今天是双 11 11 11。。

T1 星际旅行

签到题。

排序后 upper_bound 一下即可。

时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c=gc();T x=0,f=1;
		while(!isdigit(c))  f^=(c=='-'),c=gc();
		while( isdigit(c))  x=(x+(x<<2)<<1)+(c^48),c=gc();
		return f?x:-x;
	}
	inline int in()  {return Read<int>();}
}
using IO::in;
const int N=2e5+5;
int n,S,a[N];
int main(){
	n=in(),S=in();
	for(int i=1;i<=n;++i)  a[i]=in();
	sort(a+1,a+n+1);
	ll ans=0;
	for(int i=1;i<=n;++i){
		if(a[i]>=S)  break;
		int pos=upper_bound(a+1,a+i,S-a[i])-a;
		ans+=pos-1;
	}
	printf("%lld\n",ans);
	return 0;
}

T2 罔两「栖息于禅寺的妖蝶」

考场上直接打了个表,发现答案是:

( ⌊ n + m 2 ⌋ m ) \binom{\lfloor\frac{n+m}2\rfloor}{m} (m2n+m)

也可以先写一个 O ( n 2 ) O(n^2) O(n2) d p dp dp 暴力,通过那个想正解。

这里是 std 的推导:
设选出来的数从小到大是 a 1 , a 2 , ⋯   , a m a_1,a_2,\cdots,a_m a1,a2,,am,考虑令 b i = a i + i b_i=a_i+i bi=ai+i。发现 b i b_i bi 全是偶数互不相同,那么一个 b b b 就唯一对应着一个 a a a,所以问题就变成了从 n + m n+m n+m 的偶数中选出 m m m 个的方案数。

时间复杂度 O ( T ) O(T) O(T)

#include<bits/stdc++.h>
using namespace std;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c=gc();T x=0,f=1;
		while(!isdigit(c))  f^=(c=='-'),c=gc();
		while( isdigit(c))  x=(x+(x<<2)<<1)+(c^48),c=gc();
		return f?x:-x;
	}
	inline int in()  {return Read<int>();}
}
using IO::in;
const int N=2e6+5,P=998244353;
int n,m,fac[N],ifac[N];
int add(int x,int y)  {return x+y>=P?x+y-P:x+y;}
int dec(int x,int y)  {return x-y< 0?x-y+P:x-y;}
int mul(int x,int y)  {return 1ll*x*y>=P?1ll*x*y%P:x*y;}
int power(int a,int b){
	int ans=1;
	for(;b;b>>=1,a=mul(a,a))  if(b&1)  ans=mul(ans,a);
	return ans;
}
int Inv(int x)  {return power(x,P-2);}
void prework(){
	fac[0]=fac[1]=1;
	for(int i=2;i<N;++i)  fac[i]=mul(fac[i-1],i);
	ifac[N-1]=Inv(fac[N-1]);
	for(int i=N-2;~i;--i)  ifac[i]=mul(ifac[i+1],i+1);
}
int C(int n,int m)  {return n<m?0:mul(fac[n],mul(ifac[m],ifac[n-m]));}
int main(){
	prework();
	int T=in();
	while(T--){
		n=in(),m=in();
		printf("%d\n",C((n+m)>>1,m));
	}
	return 0;
}

T3 式神「八云蓝」

一道大力分类讨论的题。

设询问区间是 [ x , y ] [x,y] [x,y],对于线段树的节点 [ l , r ] [l,r] [l,r],相当于统计多少个 [ x , y ] [x,y] [x,y] 的子区间会影响 [ l , r ] [l,r] [l,r]

  • [ l , r ] [l,r] [l,r] 包含 [ x , y ] [x,y] [x,y],那么 [ x , y ] [x,y] [x,y] 的所有子区间都对 [ l , r ] [l,r] [l,r] 有贡献。
  • [ l , r ] [l,r] [l,r] [ x , y ] [x,y] [x,y] 真相交,即要排除包含关系部分,那么又要分两种情况(记 s u m sum sum [ x , y ] [x,y] [x,y] 总区间个数):
    1. l ≤ x ≤ r ≤ y l\le x\le r\le y lxry:贡献是 s u m − ( y − r ) ( y − r + 1 ) 2 sum-\frac{(y-r)(y-r+1)}2 sum2(yr)(yr+1)
    2. x ≤ l ≤ y ≤ r x\le l\le y\le r xlyr:贡献是 s u m − ( l − x ) ( l − x + 1 ) 2 sum-\frac{(l-x)(l-x+1)}2 sum2(lx)(lx+1)
    相当于减掉 [ x , y ] [x,y] [x,y] 中不与 [ l , r ] [l,r] [l,r] 相交的区间
  • [ x , y ] [x,y] [x,y] 包含 [ l , r ] [l,r] [l,r],贡献是 s u m − ( l − x ) ( l − x + 1 ) 2 − ( y − r ) ( y − r + 1 ) 2 sum-\frac{(l-x)(l-x+1)}{2}-\frac{(y-r)(y-r+1)}{2} sum2(lx)(lx+1)2(yr)(yr+1),若是非叶节点要减 2 ( l − x + 1 ) ( y − r + 1 ) 2(l-x+1)(y-r+1) 2(lx+1)(yr+1)
    1 1 1 个减的部分:排除与 [ l , r ] [l,r] [l,r] 不交的情况;
    2 2 2 个减的部分:若若完全覆盖某个节点,那么它的两个儿子均不能覆盖。所以统计时要减去 ( f a l − x + 1 ) ( y − f a r + 1 ) (fa_l-x+1)(y-fa_r+1) (falx+1)(yfar+1),表示完全覆盖父亲的情况。这里相当于是转换了一下,在父亲的时候统计减的贡献,更方便一点。

发现前两个在线段树上只有 O ( log ⁡ n ) O(\log n) O(logn) 个点,可以暴力统计。但是情况 3 3 3 是有 O ( log ⁡ n ) O(\log n) O(logn)子树,暴力会 T

如果把 x , y x,y x,y 当做未知数,情况 3 3 3 的贡献式子会化成 A x 2 + B x y + C y 2 + D x + E y + F Ax^2+Bxy+Cy^2+Dx+Ey+F Ax2+Bxy+Cy2+Dx+Ey+F 的形式,可以在线段树上维护这些系数,把子树的答案都加到父亲上来,统计的时候把 x , y x,y x,y 具体的值代进去即可。

时间复杂度 O ( q log ⁡ n ) O(q\log n) O(qlogn)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
namespace IO{
	const int Rlen=1<<22|1;
	char buf[Rlen],*p1,*p2;
	inline char gc(){
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	template<typename T>
	inline T Read(){
		char c=gc();T x=0,f=1;
		while(!isdigit(c))  f^=(c=='-'),c=gc();
		while( isdigit(c))  x=(x+(x<<2)<<1)+(c^48),c=gc();
		return f?x:-x;
	}
	inline int gi()  {return Read<int>();}
	inline ll  gl()  {return Read<ll >();}
}
using IO::gi;
using IO::gl;
const int N=5e5+5;
int n,q,op;
ll l,r,sum,last=0;
namespace SGT{
	struct Seg{ll sze,B,D,E,F;}T[N<<2];
	void pushup(int root){
		T[root].B+=T[root<<1].B+T[root<<1|1].B;
		T[root].D+=T[root<<1].D+T[root<<1|1].D;
		T[root].E+=T[root<<1].E+T[root<<1|1].E;
		T[root].F+=T[root<<1].F+T[root<<1|1].F;
		T[root].sze+=T[root<<1].sze+T[root<<1|1].sze;
	}
	#define mid ((l+r)>>1)
	void build(int root,int l,int r){
		T[root].sze=1;
		T[root].D=2*l+1,T[root].E=2*r-1,T[root].F=-(ll)l*l-(ll)r*r-l+r;
		if(l==r)  return;
		build(root<<1,l,mid),build(root<<1|1,mid+1,r);
		T[root].B+=4,T[root].D+=-4*r+4,T[root].E+=-4*l-4,T[root].F+=4ll*l*r-4*l+4*r-4;
		pushup(root);
	}
	ll Query(int root,int l,int r,int x,int y){
		if(l>=x&&r<=y){
			ll ans=0;
			ans+=(T[root].B*x*y+T[root].D*x+T[root].E*y+T[root].F+(sum-(ll)x*x-(ll)y*y)*T[root].sze);
			return ans;
		}
		ll ans=sum;
		if(l>=x)  ans-=(ll)(l-x)*(l-x+1);
		if(r<=y)  ans-=(ll)(y-r)*(y-r+1);
		if(x<=mid)  ans+=Query(root<<1,l,mid,x,y);
		if(y> mid)  ans+=Query(root<<1|1,mid+1,r,x,y);
		return ans;
	}
	#undef mid
}
void Get(ll &l,ll &r){
	l=(gl()^(last*op))%n+1,r=(gl()^(last*op))%n+1;
	if(l>r)  swap(l,r);
}
int main(){
	n=gi(),q=gi(),op=gi();
	SGT::build(1,1,n);
	while(q--){
		Get(l,r),sum=(ll)(r-l+1)*(r-l+2);
		printf("%lld\n",last=SGT::Query(1,1,n,l,r)/2);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值