D. Binary Spiders(思维+字典树)
D. Binary Spiders
[Link](Problem - D - Codeforces)
題意
給你nnn個數和一個kkk,問你最多選多少個數且滿足任意兩兩之間異或≥k\ge k≥k。
思路
考慮怎么利用一些性質來統計方案,因為涉及⊕\oplus⊕操作,我們轉化為二進制來考慮。
假設kkk的二進制最高位111為第mmm位
對于任意兩個數a,ba,ba,b如果a,ba,ba,b二進制的m+1~29m+1\sim29m+1~29不同的話,必有a⊕b≥k(由異或性質a⊕b二進制的最高為一定比m高)a\oplus b\ge k(由異或性質a\oplus b二進制的最高為一定比m高)a⊕b≥k(由異或性質a⊕b二進制的最高為一定比m高),因此前綴不同的我們可以隨便選。
再來證明對于前綴相同(二進制位m+1~29m+1\sim29m+1~29相同)的數我們最多選兩個。
假設a,b,ca,b,ca,b,c前綴相同且a⊕b≥k且a⊕c≥ka\oplus b\ge k且a\oplus c\ge ka⊕b≥k且a⊕c≥k
則有a,b二進制的第二進制的第二進制的第m位必為一個0一個1,a,c二進制的第二進制的第二進制的第m位必為一個0一個1
則b,cb,cb,c的二進制第mmm位相同且前綴相同因此b⊕c<kb\oplus c<kb⊕c<k
因此由抽屜原理,前綴相同的最多選兩個。
由上面性質,我們將所有的數按照前綴分組,對于每組前綴我們看當前組是否存在一個數和他異或≥k\ge k≥k,有貢獻就是222,無貢獻就是111。
找同組前面數和當前數異或最大值可以用字典樹維護復雜度為lognlognlogn,枚舉nnn,總復雜度為O(nlogn)O(nlogn)O(nlogn)。
分組可以用mapmapmap,然后用迭代器遍歷。
特判kkk為000的情況因為k==0k==0k==0,因為map只能存一個的下標,k==0k==0k==0時相同的數前綴相同,這些相同的數按剛才只能選兩,且下標不對。
Code
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> #include <set> #include <queue> #include <vector> #include <map> #include <bitset> #include <unordered_map> #include <cmath> #include <stack> #include <iomanip> #include <deque> #include <sstream> #define x first #define y second #define debug(x) cout<<#x<<":"<<x<<endl; using namespace std; typedef long double ld; typedef long long LL; typedef pair<int, int> PII; typedef pair<double, double> PDD; typedef unsigned long long ULL; const int N = 3e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7; const double eps = 1e-8, pi = acos(-1), inf = 1e20; #define tpyeinput int inline char nc() {static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;} inline void read(tpyeinput &sum) {char ch=nc();sum=0;while(!(ch>='0'&&ch<='9')) ch=nc();while(ch>='0'&&ch<='9') sum=(sum<<3)+(sum<<1)+(ch-48),ch=nc();} int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1}; int h[N], e[M], ne[M], w[M], idx; void add(int a, int b, int v = 0) {e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++; } int n, m, k; int a[N]; int tr[N * 30][2]; map<int, int> id; map<int, vector<int>> mp; vector<int> res; int bits(int x) {int res = 0;while (x) {x >>= 1;res ++;}return res; } void insert(int x) {int p = 0;for (int i = 30; i >= 0; i -- ) {int u = x >> i & 1;if (!tr[p][u]) tr[p][u] = ++ idx;p = tr[p][u];} } int query(int x) {int p = 0, res = 0;for (int i = 30; i >= 0; i -- ) {int u = x >> i & 1;if (!tr[p][!u]) {p = tr[p][u];res = res * 2 + u;}else {p = tr[p][!u];res = res * 2 + !u;}}return res; } int main() {ios::sync_with_stdio(false), cin.tie(0);cin >> n >> k;m = bits(k);for (int i = 1; i <= n; i ++ ) {cin >> a[i];int x = (a[i] >> m);mp[x].push_back(a[i]);id[a[i]] = i;}if (!k) {cout << n << endl;for (int i = 1; i <= n; i ++ ) cout << i << ' ';cout << endl;return 0;}map<int, vector<int>> ::iterator iter;for (iter = mp.begin(); iter != mp.end(); iter ++ ) {memset(tr, 0, sizeof (int)*2 * (idx + 1)), idx = 0;vector<int> ve = iter->second;int one = -1; bool ok = false;for (auto x : ve) {insert(x);int t = query(x);if ((t ^ x) >= k) {ok = true;res.push_back(id[t]);res.push_back(id[x]);break;}one = id[x];}if (one && !ok) res.push_back(one);}if (res.size() <= 1) cout << -1 << endl;else {cout << res.size() << endl;for (auto x : res) cout << x << ' ';cout << endl; }return 0; }總結
以上是生活随笔為你收集整理的D. Binary Spiders(思维+字典树)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MovieClip添加点击事件
- 下一篇: 第一章 DirectX 计算机图形学(上