P3940 分組(貪心+並查集)
阿新 • • 發佈:2018-12-19
因為字典序最小。
組越少 + 越前面的組size越小!
考慮資料範圍131072!好巧啊!131072 + 131072 = 262144 = 512 * 512.也就是說任意兩個元素之和小於等於512的平方。。。。
那麼我們對於一個元素i可以從512列舉,表示它和另一個元素j之和是某數的平方。
k == 1;
因為組內元素,必須有序
倒著貪心,如果當前元素i能放進上個組(上個組沒有和它之和為平方數)則放.不能放新開一個組,
不能放的那個則是兩個組的分界線。
怎麼找有沒有和元素i之和為平方數的數?
從512倒著列舉,假設列舉的數為k ,如果k*k - i在上一組就必須新開一個組。
k == 2;
也是倒著貪心,只不過當前元素能不能放進上個組的條件變了。
不能出現當前元素和上個組裡的元素i矛盾,同時也和上個組裡的元素j矛盾,而i和j也矛盾。這種情況必須新開組。
//當前元素和元素i不能在同一個小團體,前元素和元素j不能在同一個小團體,元素j和元素i不能在同一個小團體,一個組最多2個小團體。
怎麼表示這種矛盾關係呢??是不是和noip關押罪犯很像啊。
如果當前元素和元素i矛盾,就把當前元素的位置和i的位置+n,並在一起(i 的位置+ n表示i的敵人所在的位置,這樣表示i的敵人和當前元素在同一個小團體).
當然每組的元素可能重複,vector記錄元素i所對應的位置。
#include<bits/stdc++.h> using namespace std; vector<int>he[300000]; int n,k,a[150000],an[159999],fa[300000], vis[159999],ans = 1; void read(int &x) { x = 0; int f = 0; char c = getchar(); while(c < '0' || c > '9') { if(c == '-') f = 1; c = getchar(); } while(c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); } if(f) x = -x; } int find(int x) { if(fa[x] == x) return x; return fa[x] = find(fa[x]); } void unio(int x,int y) { int r1 = find(x); int r2 = find(y); fa[r1] = r2; } void solve1() { for(int i = n; i >= 1; i--) { int ha = 0; for(int j = 512; j >= 1; j--) { if(j*j < a[i]) break; if(vis[j * j - a[i]] == ans) {ha = 1; break;} } if(ha) an[++ans] = i; vis[a[i]]= ans; } printf("%d\n",ans); for(int i = ans; i > 1; i--) printf("%d ",an[i]); } void solve2() { for(int i = 2*n; i >= 1; i--) fa[i] = i; for(int i = n; i >= 1; i--) { int ha = 0; for(int j = 512; j >= 1 && ha == 0; j--) { if(j*j < a[i]) break; if(vis[j * j - a[i]] == ans) for(int k = 0; k < he[j * j -a[i]].size(); k++) { if(find(i) == find(he[j * j -a[i]][k])) {ha = 1;break;} unio(i+n,he[j * j -a[i]][k]);unio(i,he[j * j -a[i]][k]+n); } } if(ha) { an[++ans] = i; } if(vis[a[i]] != ans) { vis[a[i]] = ans; he[a[i]].clear(); } he[a[i]].push_back(i); } printf("%d\n",ans); for(int i = ans; i > 1; i--) printf("%d ",an[i]); } int main() { read(n);read(k); for(int i = 1; i <= n ;i ++) read(a[i]); if(k == 1)solve1(); else solve2(); return 0; }