5.9杂题

Day9 A. 闸机检修(贪心)

\(n\) 个闸机排成一排,有一个给定的可重集 \(A\),每次从中选择一个数 \(x\) 并删除,然后选择一段长度为 \(x\) 的区间,须满足区间内不存在崩溃的闸机,随后会有这个区间内的恰好一个闸机崩溃。你需要判断是否存在一种操作的顺序和方案,使得无论每次区间内哪一台闸机崩溃,都能够一直操作直到 \(A\) 被删空。同时,如果你认为存在,那么交互库会和你轮流操作,你每次提供所选区间,交互库决定崩溃的闸机编号,你获胜当且仅当你每次都能操作;如果你认为不存在,那么交互库也会和你轮流操作,交互库每次提供所选区间,你决定崩溃的闸机编号,你获胜当且仅当集合未被删空时交互库就不能操作了。\(n,|A|\le 5000\)

没有做出这道签到题。

不难发现按照从大到小的顺序取出 \(A\) 中的数是最优的——我方和交互库都必然会遵循这一最优策略进行操作。

正难则反,考虑什么时候会无解。一定是在某次操作时,不存在一段长度为 \(x\) 的空白区间。那么对手的最优策略就是每次让一个编号为 \(x\) 的倍数的闸机崩溃,可感性理解这样对方性价比最高。那也就是说,如果把 \(A\) 降序排序,那么一旦存在 \(i\) 使得 \((i-1)\cdot A_i>n-A_i\),那么就无解了。至于构造方案,有解时随便选即可,无解时按照如上方法构造。

#include <bits/stdc++.h>
using namespace std;
const int N=5005;
int n,m,yes,now,bk[N];
vector<int>a;
int solve(int nnn,vector<int>aaa){
	n=nnn,m=aaa.size(),a=aaa;
	sort(a.begin(),a.end(),greater<int>());//最优策略必然是从大到小地考虑区间
	for(int i=1;i<=m;i++){
		if(a[i-1]*i>n)return yes=a[i-1],1;//1~i-1步都在谋划着让a[i]填不下:a[i]*(i-1)+a[i]>n
	}
	return 0;
}
pair<int,int>get_ans0(int pre){//既然对着你卡都卡不了,自然随便选区间位置就行
	if(pre!=-1)bk[pre]=1;
	for(int i=1;i<=n;i++)bk[i]+=bk[i-1];
	for(int i=1;i<=n-a[now]+1;i++)if(bk[i-1]==bk[i+a[now]-1]){
		for(int j=n;j;j--)bk[j]-=bk[j-1];
		return make_pair(i,i+a[now++]-1);
	}
	return make_pair(-1,-1);
}
int get_ans1(pair<int,int>pre){
	for(int i=pre.first;i<=pre.second;i++)if(i%yes==0&&!bk[i])return bk[i]=1,i;
	return 0;
}//0->has solution  1->no solution

Day9 B. 轨道上行(倍增)

一条直线上有 \(n\) 个点,有 \(m\) 条火车线路,第 \(i\) 条从 \(a_i\to b_i\)(有向)。凭借一张从 \(a_i\)\(b_i\) 的票:若 \(a_i<b_i\),则一个在 \([a_i,\min(b_i,a_i+K-1)\) 的人可以免费穿梭到 \(a_i\);若 \(a_i>b_i\),则一个在 \([\max(a_i-K+1,b_i),a_i]\) 的人可以免费穿梭到 \(a_i\)。人登上一条线路后可以在任意站台下车(包括 \(a_i\))。\(q\) 次询问如果一个人想要从 \(S\)\(T\),那么最少购票多少张。\(n,m,q\le 10^6\)。TL = 7s。

一个重要的观察是每个人从 \(S\) 凭借 \(\le x\) 张票所能到达的点构成一段区间(这个观察类似 JOISC2023 passport)。而这是类似“跳”的过程,因而可以用倍增优化,处理出用 \(2^j\) 张票、从 \(i\) 能够到达的区间 \([l_{j,i},r_{j,i}]\)。每次转移是个 RMQ,可以通过 ZKW 线段树预处理(常数会比较小)。

#include <bits/stdc++.h>
using namespace std;
namespace IO {
const int buflen=1<<21;
char ch,buf[buflen],*p1=buf,*p2=buf;
int x,f;
inline char gc(){
	return p1==p2&&(p2=buf+fread(p1=buf,1,buflen,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
	x=0,f=1;ch=gc();
	while(ch<'0'||ch>'9'){if(ch=='-')f=0;ch=gc();}
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=gc();
	return f?x:-x;
}
}
using IO::read;
void print(int x){
	if(x/10)print(x/10);
	putchar(x%10+48);
}
const int N=1e6+5;
int n,K,m,q,lgn,nn,l[21][N],r[21][N],L[21][1<<21],R[21][1<<21],a[N],b[N],mxr[N],mnl[N];
int ql,qr,Q[N];
void build(int l[N],int r[N],int L[1<<21],int R[1<<21]){
	for(int i=nn+1;i<=(nn<<1);i++)L[i]=1e9,R[i]=-1e9;
	for(int i=1;i<=n;i++)L[i+nn]=l[i],R[i+nn]=r[i];
	for(int i=nn;i;i--)L[i]=min(L[i<<1],L[i<<1|1]),R[i]=max(R[i<<1],R[i<<1|1]);
}
pair<int,int>rmq(int x,int y,int L[1<<21],int R[1<<21]){
	int ansl=1e9,ansr=-1e9;
	for(x+=nn-1,y+=nn+1;x^y^1;x>>=1,y>>=1){
		if(~x&1)ansl=min(ansl,L[x^1]),ansr=max(ansr,R[x^1]);
		if(y&1)ansl=min(ansl,L[y^1]),ansr=max(ansr,R[y^1]);
	}
	return make_pair(ansl,ansr);
}
multiset<int>oo;
vector<int>qu[N];
int main(){
	freopen("ex_track3.in","r",stdin);freopen("track.out","w",stdout);
	n=read(),K=read(),m=read();
	while((1<<lgn)<=n)lgn++;nn=1<<lgn;
	int U=0;
	for(int i=1;i<=m;i++)a[i]=read(),b[i]=read();
	for(int i=1;i<=n;i++)mxr[i]=-1e9,mnl[i]=1e9;
	for(int i=1;i<=m;i++)if(a[i]>b[i]&&a[i]==40)cerr<<b[i]<<':';
	for(int i=1;i<=m;i++)if(a[i]<b[i])mxr[a[i]]=max(mxr[a[i]],b[i]);else mnl[a[i]]=min(mnl[a[i]],b[i]);
	ql=1,qr=0;
	for(int i=1;i<K;i++){
		while(ql<=qr&&mxr[Q[qr]]<=mxr[i])qr--;
		Q[++qr]=i;
		r[0][i]=max(i,mxr[Q[ql]]);
	}
	for(int i=K;i<=n;i++){
		while(ql<=qr&&Q[ql]<=i-K)ql++;
		while(ql<=qr&&mxr[Q[qr]]<=mxr[i])qr--;
		Q[++qr]=i;
		r[0][i]=max(i,mxr[Q[ql]]);
	}cerr<<';';
	ql=1,qr=0;
	for(int i=n;i>=n-K+2;i--){
		while(ql<=qr&&mnl[Q[qr]]>=mnl[i])qr--;
		Q[++qr]=i;
		l[0][i]=min(i,mnl[Q[ql]]);
	}cerr<<';';
	for(int i=n-K+1;i;i--){
		while(ql<=qr&&Q[ql]>=i+K)ql++;
		while(ql<=qr&&mnl[Q[qr]]>=mnl[i])qr--;
		Q[++qr]=i;
		l[0][i]=min(i,mnl[Q[ql]]);
	}cerr<<';';cerr<<r[0][13]<<'A';
	for(int i=1;i<=m;i++)if(a[i]<b[i])qu[a[i]].emplace_back(a[i]),qu[b[i]+1].emplace_back(-a[i]);
	for(int i=1;i<=n;i++){
		for(int o:qu[i])if(o>0)oo.insert(o);else oo.erase(oo.lower_bound(-o));
		if(oo.end()!=oo.lower_bound(i-K+1))l[0][i]=min(l[0][i],*oo.lower_bound(i-K+1));
	}
	oo.clear();
	for(int i=1;i<=n+1;i++)qu[i].clear();
	for(int i=1;i<=m;i++)if(a[i]>b[i])qu[a[i]].emplace_back(a[i]),qu[b[i]-1].emplace_back(-a[i]);
	for(int i=n;i;i--){
		for(int o:qu[i])if(o>0)oo.insert(o);else oo.erase(oo.lower_bound(-o));
		if(i==13){
			for(int j:oo)cerr<<j<<',';
		}
		if(oo.begin()!=oo.upper_bound(i+K-1))r[0][i]=max(r[0][i],*prev(oo.upper_bound(i+K-1)));
	}
	for(int j=1;j<=20;j++){
		build(l[j-1],r[j-1],L[j-1],R[j-1]);
		pair<int,int>tmp;
		for(int i=1;i<=n;i++){
			tmp=rmq(l[j-1][i],r[j-1][i],L[j-1],R[j-1]);
			l[j][i]=tmp.first,r[j][i]=tmp.second;
		}
	}cerr<<';';
	q=read();
	for(int qq=1,S,T;qq<=q;qq++){
		S=read(),T=read();
		int l_=S,r_=S;
		if(r[20][S]<T||l[20][S]>T){puts("-1");continue;}
		int cnt=0;
		pair<int,int>tmp;
		for(int j=19;~j;j--){
			tmp=rmq(l_,r_,L[j],R[j]);
			if(tmp.second<T||tmp.first>T)l_=tmp.first,r_=tmp.second,cnt+=1<<j;
		}
		if(qq==4)cerr<<l[0][S]<<' '<<r[0][S]<<'\n'<<S<<'_'<<T<<'\n'<<l_<<' '<<r_<<',';
		print(cnt+1),putchar('\n');
	}
	return 0;
}//if no solution print -1
/*
g++ -o track.exe track.cpp -O2 -Wl,--stack=100000000 -std=c++11 -Wall -Wextra
track.exe
12 1
5
1 7
10 12
3 5
8 10
5 9
7
2 11
5 8
3 12
4 6
1 9
9 10
1 4

*/
posted @ 2023-05-09 20:51  pengyule  阅读(6)  评论(0编辑  收藏  举报