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
*/