题目
KK 有一个正整数序列 a1,a2,…,an,以及一个正整数 P。KK 认为一个整数三元组 (i,j,k) 是好的,当且仅当同时满足以下条件:
- 1≤i<j<k≤n;
- P=ai×2⌊log2aj⌋+⌊log2ak⌋+2+aj×2⌊log2ak⌋+1+ak。
请你帮 KK 求出好的三元组数量。
对于 100% 的数据,1≤T≤103,1≤n≤105,∑n≤106,1≤ai<220,1≤P<260。
题解
首先考虑暴力求,O(n3),肯定不行,考虑优化
可以预处理出每个数的log下取整的2次幂,然后式子可以拆分成有k的因式和没有k的因式
,枚举k并顺便算出另一个因式的个数。可以用map存,时间复杂度O(n2),还是不行
观察式子,可以发现这个式子其实是把ai,aj,ak三个数在二进制下拼起来,组成P,所以我们枚举j,并枚举aj在P的哪个位置。枚举过程中顺便维护序列中j前后的数字个数,用来统计答案
问题
1.ak不能有前导0!!!
2.当1 << t
会爆long long
的时候,要改成1ll << t
!!!
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| #include<bits/stdc++.h> #define int long long using namespace std; int T, n; const int N = 1e5 + 10; int a[N];
unordered_map<int, int> suf, pre; int len[N], L, P, bit[62];
inline int getlen(int u) { int ans = 0; while(u) { ans ++; u >>= 1; } return ans; }
signed main() { bit[0] = 1; for(int i = 1;i <= 60;i++) bit[i] = bit[i - 1] * 2; ios::sync_with_stdio(0), cin.tie(0); cin >> T; while(T --) { pre.clear(), suf.clear(); int ans = 0; cin >> n, cin >> P, L = getlen(P);
for(int i = 1;i <= n;i++) cin >> a[i], len[i] = getlen(a[i]);
for(int i = 2;i <= n;i++) suf[a[i]]++; for(int j = 2;j < n;j++) { int i = j; pre[a[j - 1]] ++; suf[a[j]] --; for(int start = 2; start + len[i] - 1 < L;start++) { int t = (L - start - len[i] + 1); if(((P >> t) & ((1 << len[i]) - 1)) != a[i] || !((P >> (t - 1)) & 1)) continue; int before = (P >> (L - start + 1)), after = (P & ((1ll << t) - 1));
ans += pre[before] * suf[after]; }
} cout << ans << endl; } }
|