noip 2018 模拟赛15

T 1 T_1 T1——slon(1783)

Description:

对于一个表达式 S S S,形如 5 + x ∗ ( 3 + 2 ) , x + 3 ∗ x + 4 ∗ ( 5 + 3 ∗ ( 2 + x − 2 ∗ x ) ) 5+x*(3+2),x+3*x+4*(5+3*(2+x-2*x)) 5+x(3+2),x+3x+4(5+3(2+x2x)),求最小的非负数 x x x,使得表达式的值对 M M M取模后为 P P P
注意: x x x的指数不超过 1 1 1,且一个运算符号的两边一定有操作数。
∣ S ∣ ≤ 1 0 5 , 0 ≤ P ≤ M − 1 , M ≤ 1 0 6 |S|\le10^5,0\le P\le M-1,M\le 10^6 S105,0PM1,M106

Solution:

  • 表达式求值模拟题(沙雕模拟题
  • 做这种表达式求值问题,无非就是栈模拟,以及重载运算符和写一些关键函数,可以大大缩短码量和实现难度。
  • 最后,要求对 M M M取模的情况,但发现此题的 M M M比较小,那么直接 f o r for for找即可(扩展欧几里得)。

Code:

#include
using namespace std;
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i='0' and str[i]<='9'){
			int x=(str[i]-'0')%mod;
			while(str[i+1]>='0' and str[i+1]<='9') x=(x*10+str[++i]-'0')%mod;
			Stk[Top++]=(node){0,x};
		}
		
		else{
			while(Cmp(op[top-1],str[i])){
				node x=Stk[--Top],y=Stk[--Top];
				char c=op[--top];
				Stk[Top++]=calc(y,x,c);
			}
			if(str[i]==')') --top;
			else op[top++]=str[i];
		}
	}
	
	node ans=Stk[--Top];
	SREP(i,0,mod){
		if((1ll*ans.k*i+ans.b-P)%mod==0){
			printf("%d\n",i);
			break;
		}
	}
	return 0;
}

T 2 T_2 T2——bad(3835)

Description:

有一个长度为 n n n的序列 A A A
定义一个坏对 ( i , j ) (i,j) (i,j)当且仅当 i < j , A i m o d    A j = K i<j,A_i \mod A_j=K i<j,AimodAj=K
求有多少个区间满足区间不存在坏对。
n , A i ≤ 1 0 5 , 0 ≤ K ≤ 1 0 5 n,A_i\le 10^5,0\le K \le 10^5 n,Ai105,0K105

Solution:

  • 首先,坏对的定义,我们可以去掉模数,即 ( i , j ) , i < j , A i = A j ∗ x + K (i,j),i<j,A_i=A_j*x+K (i,j),i<j,Ai=Ajx+K
  • 又因为 A i ≤ 1 0 5 A_i \le 10^5 Ai105,那么,我们可以预处理出与 i i i匹配坏对的数
  • 那么我们在遍历时,对于第 i i i个数,我们要更新与之可以匹配坏对的数
  • 那么对答案的贡献即为 i − l a s t i-last ilast
  • 这样复杂度为 Θ ( n ⋅ n ) \Theta(n\cdot \sqrt n) Θ(nn )

Code:

#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);iinline bool chkmax(T &x,T y){return xinline void rd(T &x){
	x=0;char c;
	while((c=getchar())<48);
	do x=(x<<1)+(x<<3)+(c^48);
	while((c=getchar())>47);
}

const int N=1e5+2;

int n,m;

int A[N];

int tot;
struct node{
	int l,r;
	bool operator<(const node &_)const{
		return r<_.r;
	}
}B[N];

struct p50{
	void solve(){
		tot=0;
		REP(i,2,n) REP(j,1,i) if(A[j]%A[i]==m) B[++tot]=(node){j,i};
		sort(B+1,B+1+tot);
		int ans=n;
		REP(l,1,n) REP(r,l+1,n) {
			bool flag=1;
			REP(i,1,tot) {
				if(rSon[N];
	int mx[N];
	void solve(){
		SREP(i,1,N) for(int j=i;jSon[N];
	int mx[N];
	
	void solve(){
		SREP(i,m+1,N) for(int j=0;j+mm) chkmax(last,mx[A[i]]);
			ans+=i-last;
			SREP(j,0,Son[A[i]].size()) chkmax(mx[Son[A[i]][j]],i); 
		}
		printf("%lld\n",ans);
	}
}p3;

int main(){
//	freopen("bad.in","r",stdin);
//	freopen("bad.out","w",stdout);
	rd(n),rd(m);
	REP(i,1,n) rd(A[i]);
	
	if(n<=1000)p1.solve();
	else if(!m)p2.solve();
	else p3.solve();
	return 0;
}

T 3 T_3 T3——holiday(3064)

Description:

有一排城市,编号为0~n-1,对于城市 i i i,只与城市 i − 1 i-1 i1和城市 i + 1 i+1 i+1相连,且每个城市有一个价值 A i A_i Ai
现在从城市 s s s出发,有 d d d天时间。
规定相邻城市之间的花费和得到一个城市的价值的花费为 1 1 1天。
求最大价值。
2 ≤ n ≤ 1 0 5 , 0 ≤ A i ≤ 1 0 9 , 0 ≤ s ≤ n − 1 , 0 ≤ d ≤ 2 ⋅ n + n 2 2\le n\le10^5,0\le A_i\le10^9,0\le s\le n-1,0\le d \le 2\cdot n+\frac{n}{2} 2n105,0Ai109,0sn1,0d2n+2n

Solution:

  • 写部分分时,不难发现有单调性,对于每个起点 l l l,都有最优解的终点 r r r
  • 那么可以分治一个区间,进而枚举左端点,来找最优解的右端点,再用主席树来查询当前区间的贡献
  • 复杂度为 Θ ( n log ⁡ 2 n ) \Theta(n\log ^2n) Θ(nlog2n)

Code:

#include
using namespace std;
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;++i)
#define SREP(i,f,t) for(int i=(f),i##_end_=(t);i=i##_end_;--i)
#define LL long long
templateinline bool chkmin(T &x,T y){return x>y?x=y,1:0;}
templateinline bool chkmax(T &x,T y){return x=s) chkmax(r,i);
				sum++;
				val+=A[i];
			}
			
			if(l!=INF and r!=-INF) {
				if(s-lQ;
	void solve(){
		LL res=0,ans=0;
		SREP(i,0,n){
			Q.push(-A[i]);res+=A[i];
			if(i>=d)break;
			while(i+Q.size()>d)res+=Q.top(),Q.pop();
			chkmax(ans,res);
		}
		printf("%lld\n",ans);
	}
}p3;

struct p100{
	
	int B[N],tot;
	
	int Lson[N*20],Rson[N*20],root[N],tim;
	int cnt[N*20];
	LL sum[N*20];
	
	void Update(int &p,int f,int l,int r,int x){
		p=++tim;
		if(l==r){
			cnt[p]=cnt[f]+1;
			sum[p]=sum[f]+B[x];
			return;
		}
		int mid=(l+r)>>1;
		Lson[p]=Lson[f],Rson[p]=Rson[f];
		
		if(x<=mid) Update(Lson[p],Lson[f],l,mid,x);
		else Update(Rson[p],Rson[f],mid+1,r,x);
		
		cnt[p]=cnt[Lson[p]]+cnt[Rson[p]];
		sum[p]=sum[Lson[p]]+sum[Rson[p]];
	} 
	
	LL Query(int p,int f,int k,int l,int r){
		if(l==r)return 1ll*B[l]*min(k,cnt[p]);
		int mid=(l+r)>>1;
		int tmp=cnt[Rson[p]]-cnt[Rson[f]];
		if(k<=tmp) return Query(Rson[p],Rson[f],k,mid+1,r);
		else return sum[Rson[p]]-sum[Rson[f]]+Query(Lson[p],Lson[f],k-tmp,l,mid);
	}
	
	LL ans;
	
	void Solve(int ll,int lr,int rl,int rr){
		int rmid=(rl+rr)>>1,lmid=lr;
		LL Mx=0;
		REP(i,ll,lr){
			int res=(rmid-i)+min(s-i,rmid-s);
			if(d-res>0) if(chkmax(Mx,Query(root[rmid],root[i-1],d-res,1,tot))) lmid=i;
		}
		chkmax(ans,Mx);
		if(rl<=rmid-1) Solve(ll,lmid,rl,rmid-1);
		if(rmid+1<=rr) Solve(lmid,lr,rmid+1,rr);
	}
	
	void solve(){
		SREP(i,0,n)B[++tot]=A[i];
		sort(B+1,B+1+tot);
		tot=unique(B+1,B+1+tot)-B-1;
		DREP(i,n,1) A[i]=lower_bound(B+1,B+1+tot,A[i-1])-B;
		REP(i,1,n) Update(root[i],root[i-1],1,tot,A[i]);
		s++;
		Solve(1,s,s,n);
		printf("%lld\n",ans);
	}
}p4;

int main(){
//	freopen("holiday.in","r",stdin);
//	freopen("holiday.out","w",stdout);
	scanf("%d%d%d",&n,&s,&d);
	SREP(i,0,n) scanf("%d",&A[i]);
	
	if(n<=20)p1.solve();
//	else if(n<=3000)p2.solve();
	else if(!s)p3.solve();
	else p4.solve();
	return 0;
}

你可能感兴趣的:(离线赛-总结)