题解 Reverse

传送门

考场上卡常过了……但可以被 \(k \in [45000, 55000]\)\(k\) 为偶数的数据卡到1.4s左右

首先有个简单的BFS模拟思路
发现它合法的翻转半径是可以算出来的
所以这里枚举的边数可以优化,就可以卡过

至于正解,有一个 \(O(n)\) 的链表做法
发现我们实际上能访问到的点是一个区间内所有的奇/偶数点
考虑优化这个顺序访问过程
那就把整个数列存成链表,每个点指向下一个与当前点奇偶性相同且未被访问过的点
然后每访问一个区间,我们将这个区间内的点都指向右端点所指向的点
然后就没有了,每次在链表上顺序遍历就好
或者说这是路径压缩的并查集……无所谓啦

Code:
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 100010
#define ll long long
#define reg register int
#define fir first
#define sec second
#define make make_pair
//#define int long long 

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, k, m, s;
int ans[N];
bool vis[N];
queue< pair<int, int> > q;
inline int max(int a, int b) {return a>b?a:b;}
inline int min(int a, int b) {return a<b?a:b;}

namespace force{
	void solve() {
		ans[s]=0; vis[s]=1;
		q.push(make(s, 0));
		pair<int, int> u;
		const int mik=k>>1, eps=(k&1);
		while (q.size()) {
			u=q.front(); q.pop();
			for (reg i=min(mik, n-u.fir+1-eps-mik),v,lim=max(0, mik-u.fir); i>lim; --i) {
				v = u.fir+i*2-1+eps;
				if (!vis[v]) {
					ans[v]=u.sec+1;
					vis[v]=1;
					q.push(make(v, u.sec+1));
				}
			}
			for (reg i=min(mik, u.fir-eps-mik),v,lim=max(1, u.fir+mik-n); i>=lim; --i) {
				v = u.fir-i*2+1-eps;
				if (!vis[v]) {
					ans[v]=u.sec+1;
					vis[v]=1;
					q.push(make(v, u.sec+1));
				}
			}
		}
		for (reg i=1; i<=n; ++i) printf("%d ", ans[i]);
		printf("\n");
		exit(0);
	}
}

namespace task{
	int nxt[N];
	void solve() {
		ans[s]=0; vis[s]=1;
		q.push(make(s, 0));
		for (int i=n; i; --i)
			if (i+2>n) nxt[i]=-1;
			else if (vis[i]) nxt[i]=i+2;
			else nxt[i]=i+2;
		pair<int, int> u;
		const int mik=k>>1, eps=(k&1);
		while (q.size()) {
			u=q.front(); q.pop();
			//cout<<"u: "<<u.fir<<' '<<u.sec<<endl;
			int s, t, si, ti;
			
			si=max(1, mik-u.fir+1), ti=min(mik, n-u.fir+1-eps-mik);
			if (si<=ti) {
				s=u.fir+si*2-1+eps, t=u.fir+ti*2-1+eps;
				for (int i=s,to; ~i&&i<=t; i=to) {
					//assert(!vis[i]);
					to=nxt[i];
					if (!vis[i]) {
						ans[i]=u.sec+1;
						vis[i]=1;
						q.push(make(i, u.sec+1));
					}
					nxt[i]=nxt[t];
				}
			}
			
			si=max(1, u.fir+mik-n), ti=min(mik, u.fir-eps-mik);
			if (si<=ti) {
				s=u.fir-ti*2+1-eps, t=u.fir-si*2+1-eps;
				//cout<<"st: "<<s<<' '<<t<<endl;
				for (int i=s,to; ~i&&i<=t; i=to) {
					//assert(!vis[i]);
					to=nxt[i];
					if (!vis[i]) {
						ans[i]=u.sec+1;
						vis[i]=1;
						q.push(make(i, u.sec+1));
					}
					nxt[i]=nxt[t];
				}
			}
			if (s>2) nxt[s-2]=nxt[t];
		}
		for (reg i=1; i<=n; ++i) printf("%d ", ans[i]);
		printf("\n");
		//cout<<"nxt: "; for (int i=1; i<=n; ++i) cout<<nxt[i]<<' '; cout<<endl;
		exit(0);
	}
}

signed main()
{
	memset(ans, -1, sizeof(ans));
	n=read(); k=read(); m=read(); s=read();
	for (reg i=1; i<=m; ++i) vis[read()]=1;
	task::solve();
	
	return 0;
}
posted @ 2021-09-11 11:38  Administrator-09  阅读(7)  评论(0编辑  收藏  举报