分组
10.23
问题可以转化为,从后往前,选择一段最长的合法区间并分割,重复进行直到完成为止。
从std中收获一种神奇的并查集写法(下面隐藏处),准备研究研究。(按秩合并优化路径压缩??还只有一个数组??看起来就很优)
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 150000
#define LL long long
using namespace std;
inline int read(){
int x = 0, f = 1; 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;
}
int n, idc = 0, K;
int a[N], ans[N];
bool vis[N], dvis[N], issqr[N * 2];
int f[N * 2];
int getfa(int x) {
//return f[x] > 0 ? (f[x] = getfa(f[x])) : x;
return f[x] == x ? x : (f[x] = getfa(f[x]));
}
void unionn(int u, int v) {
u = getfa(u), v = getfa(v);
if (u != v) {
//if (f[u] > f[v]) swap(u, v);
//f[u] += f[v];
f[v] = u;
}
}
bool check(int u, int v) {
int s1 = getfa(u), s2 = getfa(u + N);//反点
int t1 = getfa(v), t2 = getfa(v + N);
if (s1 == t1) return 1;
if (s2 == t2) return 1;
unionn(s1, t2); unionn(s2, t1);
return 0;
}
void solve1() {
for (int i=n, j=n; i;) {
for (bool flag=1; j; j--) {
for (int k=1; k*k-a[j] < N; k++) {
if (k*k-a[j] <= 0) continue;
if ( vis[k*k-a[j]] ) { flag = 0; break;}
}
if ( !flag ) break;
vis[a[j]] = 1;
}
if ( !j ) break;
ans[++idc] = j;
for ( ; i>j; i--) vis[a[i]] = 0;
}
}
void solve2() {
//memset(f, -1, sizeof f);
for(int i=1; i<2*N; i++) f[i] = i;
for(int i=1; i*i<2*N; i++) issqr[i*i] = 1;
for(int i=n, j=n; i; ) {
for( ; j; j--) {
bool flag = 1;
if ( vis[a[j]] ) {
if ( issqr[a[j] + a[j]] ) {//当前堆内冲突
if ( dvis[a[j]] ) break;//区间内已有两个相同数字
for (int k=1; k*k-a[j]<N; k++) {
if (k*k-a[j] <= 0) continue;
if (vis[k*k-a[j]] && k*k != a[j]*2) {
flag = 0; break;
}
}
if ( !flag ) break;
dvis[a[j]] = 1;
}
}
else {//之前没有出现过
for (int k=1; k*k-a[j] < N; k++) {
if (k*k-a[j] <= 0) continue;
if ( vis[k*k-a[j]] ) {//处理并查集
if ( dvis[k*k-a[j]] || dvis[a[j]] ) { flag = 0; break;}
if ( check(k*k-a[j], a[j]) ) {flag = 0; break;}
}
}
if ( !flag ) break;
vis[a[j]] = 1;
}
}
if ( !j ) break;
ans[++idc] = j;
//for ( ; i>j; i--) f[a[i]] = f[a[i] + N] = -1, vis[a[i]] = 0, dvis[a[i]] = 0;
for ( ; i>j; i--) f[a[i]] = a[i], f[a[i] + N] = a[i] + N, vis[a[i]] = 0, dvis[a[i]] = 0;
}
}
int main() {
freopen("division.in", "r", stdin);
freopen("division.out", "w", stdout);
scanf("%d%d", &n, &K);
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
if (K == 1) solve1();
else solve2();
printf("%d\n", idc + 1);
for(int i=idc; i; i--) printf("%d ", ans[i]);
return 0;
}