A. Brick Wall 大致题意 有一堵砖墙,由砖块组成,每一个砖块都是 $1 \times k$ ($k$ 可以是任意值,每一块砖块的 $k$ 可以不一样)的方块,可以横放或者纵向放
问横放和纵放的最大差值是多少
思路 那全都横放不就行了
AC code 1 2 3 4 5 6 7 8 9 void  solve ()   {     int  _;     cin >> _;     for  (int  tc = 0 ; tc < _; ++tc) {         int  n, m;         cin >> n >> m;         cout << n * (m / 2 ) << endl;     } }
B. Minimize Inversions 大致题意 有两个数组,每次允许操作选择两个下标,在两个数组中分别操作交换这两个下标的值
问让这两个数组的逆序对数量之和最小,应该如何操作
思路 大胆猜测,把其中一个数组排序好就行了
AC code 1 2 3 4 5 6 7 8 9 10 11 12 13 14 void  solve ()   {     int  _;     cin >> _;     for  (int  tc = 0 ; tc < _; ++tc) {         int  n;         cin >> n;         vector<pair<int , int >> data (n);         for  (auto & [fst, snd]: data) cin >> fst;         for  (auto & [fst, snd]: data) cin >> snd;         sort (data.begin (), data.end ());         for  (int  i = 0 ; i < n; ++i) cout << data[i].first << " \n" [i == n - 1 ];         for  (int  i = 0 ; i < n; ++i) cout << data[i].second << " \n" [i == n - 1 ];     } }
C. XOR-distance 大致题意 有两个数,现在希望找到一个 $x$,使得 $\left | (a \oplus x) - (b \oplus x)\right |$ 最小,且 $x \in [0, r]$
思路 由于是异或运算,且最后取了绝对值,实际上对于每一个比特位而言,$x$ 取什么毫无意义。因为对于这个比特位而言,$x$ 取任意值,不同的则还是不同,相同的则还是相同
所以考虑的情况是,某个高的比特位发生了 $a \neq b$ 的情况,这个时候需要努力去构造另外一个值的下面的比特位,使得高位的这个差值带来的影响尽可能小
AC code 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 #define  int long long void  solve ()   {     int  _;     cin >> _;     for  (int  tc = 0 ; tc < _; ++tc) {         int  a, b, r;         cin >> a >> b >> r;         auto  f = [&](const  int  v, int  i) {             int  rs = r, res = 0 ;             for  (; i >= 0 ; --i) {                 if  ((a & 1LL  << i) == (b & 1LL  << i)) res += 1LL  << i;                 else  if  (v & 1LL  << i) {                     if  (rs >= 1LL  << i) rs -= 1LL  << i;                     else  res += 2  * (1LL  << i);                 }             }             return  res;         };         int  ans = 0 ;         for  (int  i = 63 ; i >= 0 ; --i) {             if  ((a & 1LL  << i) == (b & 1LL  << i)) continue ;             ans = 1  + f (a & 1LL  << i ? a : b, i - 1 );             break ;         }         cout << ans << endl;     } }
D. Blocking Elements 大致题意 从一个数组中,取出一部分值,将整个数组拆成 $n$ 份,将每一份内进行求和,同时取出的值也作为单独的一份进行求和,这些求和值中最大的就是这个数组的代价
问代价最小是多少
思路 显然,可以二分,问题是如何检查二分的答案是否合法,这里设二分得到的答案是 $v$
可以通过 dp 的方式来计算,令 dp[i] 作为第 $i$ 个值被选中后,$[1, i]$ 中被选中的那些值的总代价
可以得到 $dp[i] = dp[j] + a[i]$,其中 $j \in [l, i), \sum_{x=l}^{i-1} a_x \leq v$
故搞个优先队列维护一下即可
AC code 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 #define  int long long void  solve ()   {     int  _;     cin >> _;     for  (int  tc = 0 ; tc < _; ++tc) {         int  n;         cin >> n;         vector<int > data (n) , dp (n)  ;         for  (auto & i: data) cin >> i;         auto  check = [&](const  int  v) {             priority_queue<pair<int , int >, vector<pair<int , int >>, greater<>> pq;             pq.emplace (0 , -1 );             int  l = 0 , tot = 0 ;             for  (int  i = 0 ; i < n; ++i) {                 if  (pq.empty ()) dp[i] = data[i];                 else  dp[i] = pq.top ().first + data[i];                 tot += data[i];                 while  (tot > v) {                     tot -= data[l];                     ++l;                 }                 pq.emplace (dp[i], i);                 while  (!pq.empty () && pq.top ().second + 1  < l) pq.pop ();             }             while  (!pq.empty ()) {                 if  (pq.top ().first <= v) return  true ;                 pq.pop ();             }             return  false ;         };         int  l = 0 , r = 1e18 ;         while  (l + 1  < r) {             if  (const  int  mid = l + r >> 1 ; check (mid)) r = mid;             else  l = mid;         }         cout << r << endl;     } }
E. ace5 and Task Order 大致题意 有一个未知的数组 $a$ 和一个未知的初始值 $x$
每次允许你询问一个 $i$,若
$a_i < x$,则返回 <,且 $x \leftarrow x - 1$ $a_i > x$,则返回 >,且 $x \leftarrow x + 1$ $a_i = x$,则返回 = 要求求出原始数组
思路 因为不断轮询同一个值,必然最后 $x$ 和它相同
这之后再询问别的值,可以得到它们的关系,同时再询问一次之前的那个值,就可以恢复回来
可以考虑类似快排的方式进行操作即可。注意可以考虑随机函数避免被数据恶心
AC code 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 void  solve ()   {     int  _;     cin >> _;     for  (int  tc = 0 ; tc < _; ++tc) {         int  n;         cin >> n;         vector<int > pos (n + 1 )  ;         for  (int  i = 1 ; i <= n; ++i) pos[i] = i;         auto  pre = [&](const  int  i) {             while  (true ) {                 cout << "? "  << i << endl;                 cout.flush ();                 char  tmp;                 cin >> tmp;                 if  (tmp == '=' ) return ;             }         };         auto  check = [&](const  int  i, const  int  base) {             cout << "? "  << i << endl;             cout.flush ();             char  tmp, temp;             cin >> tmp;             cout << "? "  << base << endl;             cout.flush ();             cin >> temp;             return  tmp == '<' ;         };         function<void (int , int )> qs = [&](const  int  l, const  int  r) {             if  (l >= r) return ;             swap (pos[rand () % (r - l) + l], pos[r]);             pre (pos[r]);             int  c = l;             for  (int  i = l; i < r; ++i) if  (check (pos[i], pos[r])) swap (pos[c++], pos[i]);             swap (pos[c], pos[r]);             qs (l, c - 1 );             qs (c + 1 , r);         };         qs (1 , n);         vector<int > ans (n + 1 )  ;         for  (int  i = 1 ; i <= n; ++i) ans[pos[i]] = i;         cout << "! " ;         for  (int  i = 1 ; i <= n; ++i) cout << ans[i] << " \n" [i == n];         cout.flush ();     } }