[CSP-S模拟测试]:Reverse(模拟+暴力+剪枝)

题目描述

  小$G$有一个长度为$n$的$01$串$T$,其中只有$T_S=1$,其余位置都是$0$。现在小$G$可以进行若干次以下操作:
  $\bullet$选择一个长度为K的连续子串($K$是给定的常数),翻转这个子串。
  对于每个$i,i\in[1,n]$,小$G$想知道最少要进行多少次操作使得$T_i=1$。特别的,有$m$个“禁止位置”,你需要保证在操作过程中$1$始终不在任何一个禁止位置上。


输入格式

  从文件$reverse.in$中读入数据。
  第一行四个整数$n,K,m,S$。
  接下来一行$m$个整数表示禁止位置。


输出格式

  输出到文件$reverse.out$中。
  输出一行$n$个整数,对于第$i$个整数,如果可以通过若干次操作使得$T_i=1$,输出最小操作次数,否则输出$−1$。


样例

样例输入1:

6 2 0 1

样例输出1:

0 1 2 3 4 5

样例输入2:

10 4 3 3
2 5 10

样例输出2:

2 -1 0 1 -1 1 2 3 2 -1


数据范围与提示

对于所有数据,有$1\leqslant n\leqslant 10^5,1\leqslant S,k\leqslant n,0\leqslant m\leqslant n$。
保证$S$不是禁止位置,但禁止位置可能有重复。
$\bullet Subtask1(24\%)$,$n\leqslant 10$。
$\bullet Subtask2(22\%)$,$n\leqslant 10^3$。
$\bullet Subtask3(3\%)$,$k=1$。
$\bullet Subtask4(8\%)$,$k=2$。
$\bullet Subtask5(43\%)$,没有特殊的约束。


题解

首先解释一下题意,翻转子串指的是将其左右颠倒,而不是异或……

我也不知道为什么会理解错,老是死在语文……

就是一道大模拟,正解用$set$维护,但是可以疯狂加剪枝,但是理论时间复杂度还是线性的,具体剪枝看代码吧,满眼都是泪哇……

不过话说考试的时候看样例找规律能水到$11$分我也是满足了……

时间复杂度:$\Theta(n)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,K,m,S;
bool vis[100001];
int L[100001],R[100001];
int dis[100001];
queue<int> q;
void BFS()
{
	q.push(S);
	vis[S]=1;
	while(!q.empty())
	{
		int x=q.front();q.pop();
		for(int i=max(1,x-K);i<=min(x,n-K);i++)
		{
			int t=K-x+(i<<1);
			if(t>x)break;
			if(!vis[t]&&dis[t]!=-1)
			{
				vis[t]=1;
				dis[t]=dis[x]+1;
				q.push(t);
			}
			if(dis[t]!=-1)i=max(i,(x+R[t]-K)>>1);
			L[t]=min(L[t],K-x+max(1,x-K)*2);
			R[t]=max(R[t],K-x+min(x,n-K)*2);
		}
		for(int i=min(x,n-K);i>=max(1,x-K);i--)
		{
			int t=K-x+(i<<1);
			if(t<=x)break;
			if(!vis[t]&&dis[t]!=-1)
			{
				vis[t]=1;
				dis[t]=dis[x]+1;
				q.push(t);
			}
			if(dis[t]!=-1)i=min(i,(x+L[t]-K)>>1);
			L[t]=min(L[t],K-x+max(1,x-K)*2);
			R[t]=max(R[t],K-x+min(x,n-K)*2);
		}
	}
}
int main()
{
	scanf("%d%d%d%d",&n,&K,&m,&S);K--;
	memset(dis,0x3f,sizeof(dis));dis[S]=0;
	for(int i=1;i<=n;i++)L[i]=R[i]=i;
	while(m--)
	{
		int x;scanf("%d",&x);
		dis[x]=-1;
	}
	BFS();
	for(int i=1;i<=n;i++)
	{
		if(dis[i]==0x3f3f3f3f)printf("-1 ");
		else printf("%d ",dis[i]);
	}
	return 0;
}

rp++

猜你喜欢

转载自www.cnblogs.com/wzc521/p/11623155.html