JZOJ6847. 【2020.11.03提高组模拟】通往强者之路 题解

一道不错的题目。
首先先%%%FK大佬教我做这道题和它的亿点细节
如果只有n,n+1,答案循环节为n+1
如果只有n,n-1,答案循环节为n
现在有n-1,n,n+1
那么n-1,n不会变,n+1在每n位中会往后移动1位
并且呢,一个n-1和n+1相碰会变成n(n+1在前)
那么记last,next为n+1上一个n-1,n-1下一个n+1
当a[x%n]==n-1时,判断时间是否大于x
时间是(x-last[x])*(x+1),如果大于,输出n,否则输出n-1
当a[x%(n+1)]==n+1时同理
如果以上情况都不满足,输出n
细节:
1,记得它是一个环
2,两个条件可能满足,注意特判
3,%(n+1)可能等于n,将a[n]求出来。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std; 
ll i,j,k,m,n,o,p,l,s,t,times;
ll a[1000005],b[1000005],g[1000005],c[1000005],nxt[1000005],las[1000005],z[1000005],bz[1000005];
void read(ll &x)
{
	char ch=getchar();x=0;
	while (ch<'0'||ch>'9') ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-48,ch=getchar();
}
int main()
{
	freopen("way.in","r",stdin);
	freopen("way.out","w",stdout);
	read(times);
	while (times--)
	{
		memset(las,-1,sizeof(las));
		memset(nxt,-1,sizeof(nxt));memset(g,0,sizeof(g));
		memset(bz,0,sizeof(bz));z[0]=0;
		read(n),read(m);
		for (i=0;i<=n-1;i++) read(a[i]);
		for (i=0;i<=(n-1)*2;i++) b[i]=a[i%n];
		for (i=1;i<=(n-1)*2;i++)
		{
			if (b[i]==n+1&&!bz[i%n]) z[++z[0]]=i,bz[i%n]=1;
			if (b[i]==n-1&&nxt[z[z[0]]%n]==-1&&z[0]&&!g[i%n]) 
			{
				if (z[z[0]]==70)
				{
					int adg=0;
				}
				nxt[z[z[0]]%n]=i%n,z[0]--,g[i%n]=1;
			}
		}
		z[0]=0;memset(bz,0,sizeof(bz));memset(g,0,sizeof(g));
		for (i=1;i<=(n-1)*2;i++)
		{
			if (b[i]==n+1&&!bz[i%n]) z[++z[0]]=i,bz[i%n]=1;
			if (b[i]==n-1&&las[i%n]==-1&&z[0]&&!g[z[z[0]]%n])
			{
				las[i%n]=z[z[0]]%n,g[z[z[0]]%n]=1,z[0]--;
			}
		}
		memset(bz,0,sizeof(bz));z[0]=0;
		for (i=0;i<=n-1;i++) a[n]+=(a[i]<=n-i);
		for (i=1;i<=m;i++) 
		{
			if (i==19)
			{
				int gsf=0;
			}
			read(c[i]);
			ll x=c[i];
			if (a[x%(n+1)]==n+1&&a[x%n]==n-1)
			{
				ll y=x%n,Y=x%(n+1);
				if (las[y]==-1) printf("%lld ",n-1);
				else if (nxt[Y]==-1) printf("%lld ",n+1);
				else if ((y-las[y]+n)%n*(n+1)>c[i]) printf("%lld ",n-1);
				else if ((nxt[Y]-Y+n)%n*(n+1)>c[i]) printf("%lld ",n+1);
				else printf("%lld ",n);
			} else if (a[x%n]==n-1)
			{
				ll y=x%n;
				if (las[y]==-1) printf("%lld ",n-1);
				else {
					if ((y-las[y]+n)%n*(n+1)<=c[i]) printf("%lld ",n);
					else printf("%lld ",n-1);
				}
			} 
			else if (a[x%(n+1)]==n+1)
			{
				ll y=x%(n+1);
				if (nxt[y]==-1) printf("%lld ",n+1);
				else {
					if ((nxt[y]-y+n)%n*(n+1)<=c[i]) printf("%lld ",n);
					else printf("%lld ",n+1);
				}
			} else printf("%lld ",n);
		}
		puts("");
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值