翻译
有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;
}