[NOI十连测] 二进制的世界

题意

  给定一个长度为 n 的序列 A , 以及一种位运算 Op .

  对于每个位置 x , 求 $\min_{y < x} A[y] ~ Op ~ A[x]$ .

  n <= 100000, 0 <= A[i] <= 65536 .

一个高效的Trick

  我们可以贪心地尽可能使高的位大.

  g[x] 表示前 8 位为 x 的一个 vector .

  我们维护 g 进行剪枝.

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cctype>
 5 #include <vector>
 6 using namespace std;
 7 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 8 inline int rd(void) {
 9     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1;
10     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f;
11 }
12
13 const int N = 100005;
14
15 int n, Ty, a[N]; char Op; vector<int> g[256];
16 inline int Compute(int x, int y) { return Op == ‘a‘ ? (x & y) : Op == ‘o‘ ? (x | y) : (x ^ y); }
17
18 int main(void) {
19     #ifndef ONLINE_JUDGE
20         freopen("bin.in", "r", stdin);
21     #endif
22
23     n = rd(); for (Op = getchar(); !isalpha(Op); Op = getchar()); Ty = rd();
24     F(i, 1, n) a[i] = rd();
25
26     F(i, 2, n) {
27         g[a[i-1] >> 8].push_back(a[i-1]);
28
29         static vector<int> List; List.clear(); int id = -1;
30         F(j, 0, 255) if (g[j].size() > 0) {
31             if (id == -1)
32                 List.push_back(id = j);
33             else if (Compute(a[i], j << 8) > Compute(a[i], id << 8))
34                 List.clear(), List.push_back(id = j);
35             else if (Compute(a[i], j << 8) == Compute(a[i], id << 8))
36                 List.push_back(j);
37         }
38
39         int res = -1, cnt = 0;
40         for (vector<int>::iterator pos = List.begin(); pos != List.end(); pos++)
41             for (vector<int>::iterator it = g[*pos].begin(); it != g[*pos].end(); it++) {
42                 int t = Compute(a[i], *it);
43                 if (t > res) res = t, cnt = 1; else if (t == res) cnt++;
44             }
45         !Ty ? printf("%d\n", res) : printf("%d %d\n", res, cnt);
46     }
47
48     return 0;
49 }

平衡规划

  类似之前的做法, 但是我们后 8 位直接存下来.

  f[i][j] 表示之前某个前 8 位为 i 的数, 与一个后 8 位为 j 的数, 进行 Op 运算时, 后 8 位的最大值.

  查询  设 x 的前 8 位为 A , 后 8 位为 B .

      枚举之前某个数的前 8 位 X , 若 f[X][B] 存在, 就用 (X Op A) << 8 + f[X][B] 更新答案.

  维护  枚举后 8 位 Y , 将 f[A][Y] 进行更新.

时间: 2025-01-07 02:58:31

[NOI十连测] 二进制的世界的相关文章

NOI十连测 第五测 T1

1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<iostream> 5 #include<algorithm> 6 int f[257][257],n,type,V[257],g[257][257],ans,cnt; 7 char op[204]; 8 int read(){ 9 int t=0,f=1;char ch=getchar(); 10 while

NOI十连测 第四测 T3

思路: 算法一:可以n^2找出每个点的权值,然后n^2做完,预计得分10 算法二:随机找点然后每次找最高..貌似只有10分?然而考试的时候煞笔了,边界设成inf.. 算法三:随机找几个点,然后随机爬山,听说有50~70 算法四:考虑将列分治,每次分成2部分,找出每部分边界的最大值,判断最大值左边和右边的大小,然后往大的那一边递归,预计得分70 算法五:不仅将列分治,并且将行分治,将一个n*n的矩阵划分,然后递归找,预计得分100 1 #include<bits/stdc++.h> 2 #inc

NOI十连测 第四测 T1

思路:首先每个蚂蚁移速相同,而且碰到就转头,这其实等价于擦肩而过! 看到2n个数互不相同就觉得方便多了:枚举每个数字往左或者往右作为最慢,然后考虑其他蚂蚁有多少种走路方向. (1),走的距离大于m/2 假如红色描述的是一个蚂蚁的移动轨迹,那么蓝色部分左边的蚂蚁只能向左走,蓝色右边的蚂蚁只能向右走. 而蓝色部分中的蚂蚁可以向左也可以向右,方案数为2^n,n为蓝色部分蚂蚁数量. (2),走的距离小于m/2 如图,则蓝色部分左边的蚂蚁只能向左,蓝色部分右边的蚂蚁只能向右.而蓝色部分中间不能有蚂蚁!,这

NOI十连测 DAY3 T1

这么二逼的题考试的时候我想了好久,我真是太弱了... 首先,由于ans都乘上了i*(i-1)/2,实际上要求的就是每个数的所有可能出现次数*这个数的权值. 我们发现,每个数的本质是一样的,我们记一个sum为数的总和,这样只要统计一次就OK了. 我们把每次的选择抽象成有向边,每个状态视为点,这样就构成一个有根树. 如图 我们只考虑1对答案的贡献.如图,在每层计算当前合并对答案的贡献,也就是要能得知我在这个节点选择合并1或者1的联通块,那么我能覆盖到几个叶子节点? 那么就变成O(n)的组合数学题了.

BZOJ NOI十连测 第一测 T2

思路:看到这题,就感觉是一道很熟悉的题目: http://www.cnblogs.com/qzqzgfy/p/5535821.html 只不过这题的K最多可以到N,而且边权不再只是1,考试的时候yy了一下做法: 找k次直径,第一次把边取反,要是第二次再取到同样的边,那就把它变成0,毕竟每条边只经过2次嘛,YY的很好,实际上,交上去,5分TAT 后来听以为神犇说不是取0,而是继续取反,每条边取一次就取反一次,woc.. 1 #include<cstdio> 2 #include<cmath

NOI十连测 第五测 T2

思路:考虑建立可持久化线段树,第一层维护的是i这个位置的next位置,第二层,维护的是接下来走这个字符会到哪个节点. 感觉很巧妙啊,不愧是Claris 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 int v[18000005],l[18000005],r[18000005],sz; 7 i

BZOJ NOI十连测 第一测 T1

思路:首先考虑t=1的情况,t等于1,那么所有位置的颜色相同,我们不用考虑概率的问题,那么,k+d*x在模d下都相等,我们考虑预处理一个数组s[i][j],代表d为i,起始位置为j的等差数列的和,这个可以证明,当模小于等于sqrt(n)的时候可以完美解决,时间复杂度为N^1.5,对于d大于sqrt(n)的情况,只需要暴力枚举就可以了. 再考虑t>=2的情况,我们选的颜色一定是颜色数最少的那个,颜色数最少的颜色的期望绝对是最小的,然后,我们分k的左边和k的右边进行计算,我们这里称呼k+d*x的位置

NOI十连测 第六测 T1

思路: 用treap动态维护,记一个sum1,sum2,注意!,写treap如果有删除操作,千万不能把权值相同的分开来..,这在删除的时候会进入死循环,这是一个惨痛的教训... 1 #include<cstdio> 2 #include<cmath> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<time.h> 7 #define l

BZOJ NOI十连测 第二测 T2

思路:20%可以搜索.. 1 #include<algorithm> 2 #include<cstdio> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 #include<time.h> 7 #define ll long long 8 const ll Mod=998244353; 9 ll jc[300005],jcny[300005]; 10 int n