1 条题解
-
0
首先声明一个概念:表示:的二进制的最高有效位,即的二进制表示的最高一位。比如。
首先, 对于两条鱼:
- 如果,一定能吃掉,并且吃掉后一定不会减少()。
- 如果,一定不能吃掉。
需要注意的就是的情况,如果该情况能吃掉,则吃掉后一定会减少( )。
在任何时候,我们都应该尽可能多地吃掉左边 较小的鱼,也就是只要小就一直吃,而如果一个一个判断,时间复杂度肯定是不够的 ,所以要用预处理的思想,用一个数组来预处理一下,表示前面(包括)最后一条(也就是离最近的那条)的鱼的下标。如果当前在位置,在和之间的鱼肯定都可以吃,直接将移到的位置,并让异或上两条鱼之间的每条鱼的重量即可,而直接一个异或也一定会超时,需要预处理一下区间的异或和,区间问题就很容易想到前缀和,开一个数组,就表示“从这条鱼开始,还没遇到下一个 的鱼”,即从第条鱼~第条鱼的前缀异或和。而对于大的鱼,直接就可以了。对于和相等的鱼,每次判断一下它的重量和哪个大,如果就吃掉,否则就,因为一直会减少,所以最多只会执行次运算,时间复杂度可以通过。
接下来就是思考如何预处理和数组:计当前,从~遍历可能的每一位:
- 对于数组:
- 如果,左边第一个的位置就是,
- 如果,就递推,
- 对于数组:
- 如果,,区间中没有鱼,
- 如果,区间中加了条鱼,
预处理完后,从第条鱼开始从右向左模拟即可。
时间复杂度:接近
#include <iostream> #include <algorithm> #include <vector> #define endl '\n' using namespace std; void solve(){ int n, q; cin >> n >> q; vector<int> w(n); for(int i = 0; i < n; i++){ cin >> w[i]; } vector<vector<int>> left(n, vector<int> (31, -1)); vector<vector<int>> pre(n, vector<int> (31, 0)); for(int i = 0; i < n; i++){ if(i > 0){ left[i] = left[i - 1]; pre[i] = pre[i - 1]; } int d = __lg(w[i]); for(int j = 0; j <= d; j++){ left[i][j] = i; pre[i][j] = 0; } for(int j = d + 1; j <= 30; j++){ pre[i][j] ^= w[i]; } } while(q--){ int x; cin >> x; int j = n - 1; int res = 0; while(x > 0 && j >= 0){ int d = __lg(x); int k = left[j][d]; x ^= pre[j][d]; j = k; if(j == -1) break; if(x < w[j]) break; x ^= w[j]; j--; } res = n - 1 - j; cout << res << ' '; } cout << endl; } int main(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int T; cin >> T; while(T--){ solve(); } return 0; }
- 1
信息
- ID
- 2275
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 9
- 标签
- (无)
- 递交数
- 13
- 已通过
- 2
- 上传者