UVA12174 Shuffle

我们假想有一个长为s的窗口从输入序列a的a[0]开始滑动直至窗口离开序列为止,我们会得到n+s个段编号0~n+s-1。其中前s-1个序列(编号0~n-2)是不完整的(长度不是s)且分别以a[0],a[1]...a[s-1]为结尾,移动窗口只会添加元素,从编号n的窗口开始(包括编号n)窗口包含的元素也不完整,且分别以a[n+s-1].....a[n-1]为结尾,这些窗口移动时只会删除元素。我们考虑这些窗口,在滑动窗口的过程中我们容易记录每个数出现的次数,从而统计出窗口中出现次数为1的数的个数cnt,当cnt与区间长度相等时,这个区间就可以作为一次“完整”的随机播放(称这些窗口为可行窗口),即在窗口的最后一个元素后随机播放序列重新生成。我们只需从前s个窗口中的可行窗口开始,看它的后面第s个窗口是否也可行,直到所有窗口都被考虑完。若过程中所有的窗口均可行,我们就得到了一个对输入序列的划分,ans+1;特别的,当n<=s的时候,如果第n-1个窗口是可行的,说明输入序列中每个元素都只出现了一次,可能的答案数一定是s。

AC代码如下:

#include <cstdio>
#include <cstring>

using namespace std;

int a[100005*3],ok[100005*2],c[100005];
int main(int argc, char const *argv[])
{
	int T;
	scanf("%d", &T);
	while(T--)
	{
		int s,n,cnt=0;
		scanf("%d %d", &s, &n);
		for(int i=0;i<n;i++)
		scanf("%d", &a[i+s-1]);
		memset(c,0,sizeof(c));
		memset(ok,0,sizeof(ok));
		for(int i=0;i<n+s;i++)
		{
			if(i>s-1)
			{
				if(c[a[i-1]]==1) cnt--;
				else if(c[a[i-1]]==2) cnt++;
				c[a[i-1]]--;
			}
			if(i<=n-1)
			{
				if(c[a[i+s-1]]==0) cnt++;
				else if(c[a[i+s-1]]==1) cnt--;
				c[a[i+s-1]]++;
			}
			if(i<=s&&cnt==i+1)
				ok[i]=1;
			else if(i>n-1&&cnt==s-i+n-1)
				ok[i]=1;
			if(i>=s&&i<=n-1&&cnt==s)
				ok[i]++;
		}
		int ans=0;
		if(n<=s&&ok[n-1])
			ans=s;
		else
		{
			for(int i=0;i<s;i++)
			{
				int okk=1;
				if(ok[i])
				{
					for(int j=i+s;j<n+s-1;j+=s)
					{
						if(!ok[j])
						{
							okk=0;
							break;
						}
					}
					if(okk) ans++;
				}
			}
		}
		printf("%d\n", ans);
	}
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值