[Codeforces1045B][乱搞] Space Isaac

33 篇文章 0 订阅
10 篇文章 0 订阅

翻译

有0~m-1的数被分成了两个集合
每次你可以从两个集合中任取一个数做加法并对m取模
问最后0~m-1中不能被组合出来的数有多少个
会给出你A集合 大小不超过200000
m<=1e9

题解

比赛的时候想不到…
不妨先看一个数在什么情况下不能被表示出来
设这个数为P
如果有一个数x在A集合 显然(P-x)mod m也要在A集合
否则显然可以表示出这个数
x可以分为两段 小于P和大于P的情况
当x<P时 P-x也会

P时 P-x也会>P
我们考虑枚举分段点
设这个点为i
我们要找的P就等于了a[1]+a[i]
对于a[2] 我们让他与a[i-1]匹配
如果不匹配 我们肯定能在B集合中找到一个数 使之要不与a[2]能组成P 或者与a[i-1]能组成P
相当于要判定i之前是回文串
i之后也是同理
把原数组变为b[i]=a[i+1]-a[i]
枚举端点跑hash即可

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#define ULL unsigned long long
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
const ULL HA=569;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
int n,m;
int a[210000],b[210000];
ULL ha1[210000],ha2[210000],tmp[210000];
int gg[210000],ans;
void pre()
{
	for(int i=1;i<n;i++)ha1[i]=ha1[i-1]*HA+(ULL)b[i];
	for(int i=n-1;i>=1;i--)ha2[i]=ha2[i+1]*HA+(ULL)b[i];
}
ULL get1(int l,int r){return ha1[r]-ha1[l-1]*tmp[r-l+1];}
ULL get2(int l,int r){return ha2[l]-ha2[r+1]*tmp[r-l+1];}
bool ok(int l,int r){return get1(l,r)==get2(l,r);}
int main()
{
	//freopen("g.in","r",stdin);
	n=read();m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<n;i++)b[i]=a[i+1]-a[i];
	tmp[0]=1;
	for(int i=1;i<=n;i++)tmp[i]=tmp[i-1]*HA;
	pre();
	for(int i=1;i<=n;i++)
	{
		bool bk=true;
		if(i!=1)bk&=ok(1,i-1);
		if(i!=n)
		{
			bk&=(a[1]+a[i]+m==a[i+1]+a[n]);
			if(i!=n-1)bk&=ok(i+1,n-1);
		}
		if(bk)gg[++ans]=(a[1]+a[i])%m;
	}
	printf("%d\n",ans);sort(gg+1,gg+1+ans);
	for(int i=1;i<ans;i++)print(gg[i]);
	if(ans)printf("%d\n",gg[ans]);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值