我们定义第一个集合为a, 第二个集合为b
先把a数组排序, 然后我们会以线段的形式得到b集合。
我们先用a[ 1 ]去和 b 中的元素结合, 只有size(a) 个数字未被覆盖, 我们从这些数组中选答案。
枚举这些数字, 什么情况下才它是答案呢, 就是移到a[ 2 ], a[ 3 ], a[ 4 ], 它都是未被覆盖的数组,
这个东西可以用hash值维护一下就能O(1)check啦。
#include#define LL long long#define LD long double#define ull unsigned long long#define fi first#define se second#define mk make_pair#define PLL pair #define PLI pair #define PII pair #define SZ(x) ((int)x.size())#define ALL(x) (x).begin(), (x).end()using namespace std;const int N = 4e5 + 7;const int inf = 0x3f3f3f3f;const LL INF = 0x3f3f3f3f3f3f3f3f;const int mod = 1e9 + 7;const double eps = 1e-8;const double PI = acos(-1);template inline void add(T& a, S b) {a += b; if(a >= mod) a -= mod;}template inline void sub(T& a, S b) {a -= b; if(a < 0) a += mod;}template inline bool chkmax(T& a, S b) { return a < b ? a = b, true : false;}template inline bool chkmin(T& a, S b) { return a > b ? a = b, true : false;}int n, m, a[N];vector seg;vector vc;vector ans;ull HashVal;ull hs[N], Pow[N];ull getHash(int L, int R) { return hs[R] - hs[L - 1] * Pow[R - L + 1];}int main() { for(int i = Pow[0] = 1; i < N; i++) Pow[i] = Pow[i - 1] * 23333; scanf("%d%d", &n, &m); if(n == 0 || n == m) return puts("0"), 0; for(int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + 1 + n); a[n + 1] = m; a[0] = -1; for(int i = 0; i <= n; i++) if(a[i] + 1 < a[i + 1]) seg.push_back(mk(a[i] + 1, a[i + 1] - 1)); seg.push_back(mk(-1, -1)); seg.push_back(mk(m, m)); sort(ALL(seg)); for(int i = 0; i < SZ(seg) - 1; i++) for(int j = seg[i].se + 1; j < seg[i + 1].fi; j++) vc.push_back((j + a[1]) % m), vc.push_back((j + a[1]) % m - m); sort(ALL(vc)); for(int i = n - 1; i >= 1; i--) HashVal *= 23333, HashVal += a[i + 1] - a[i]; n--; for(int i = 1; i < SZ(vc); i++) hs[i] = hs[i - 1] * 23333 + vc[i] - vc[i - 1]; for(int i = SZ(vc) / 2; i < SZ(vc); i++) if(getHash(i - n + 1, i) == HashVal) ans.push_back(vc[i]); printf("%d\n", SZ(ans)); for(auto& t : ans) printf("%d ", t); if(SZ(ans))puts(""); return 0;}/**/