zoukankan      html  css  js  c++  java
  • Kick Start 2019 Round H. Elevanagram

    设共有 $N = sum_{i=1}^{9} A_i$ 个数字。先把 $N$ 个数字任意分成两组 $A$ 和 $B$,$A$ 中有 $N_A = floor{N/2}$ 个数字,$B$ 中有 $N_B=ceil{N/2}$ 个数字。将 $A$ 中数字之和记作 $S_A$,$B$ 中数字之和记作 $S_B$。若 $(S_A - S_B) mod 11 e 0$,再进行调整。

    考虑通过交换 $A$、$B$ 中的数字来改变 $S_A - S_B$ 的值。若有解一定能通过若干次交换操作使得 $S_A - S_B mod 11 = 0$。用 $(a, b)$ 表示将 $A$ 中的数字 $a$ 与 $B$ 中的数字 $b$ 进行交换,交换 $a, b$ 之后 $S_A - S_B$ 的变化量是 $-2(a - b)$。

    注意到若存在两个数字 $i, j$ 都出现了至少 $10$ 次,则答案一定是 YES。因为当 $k$ 取遍 $1$ 到 $10$,$2k(i - j)$ 也取遍 $1$ 到 $10$(在模 $11$ 的意义下)。

    若每个数字都出现了不到 $10$ 次,可以用 DP 解决。令 $f[i][j][k]$ 表示从 $A$ 中取出 $1, 2, dots, i$ 这 $i$ 种数字共 $j$ 个且取出的数字之和模 $11$ 等于 $k$ 是否有可能。对 $B$ 也进行同样的 DP。
    补充:看了官方题解之后发现这个 DP 不必分别对 $A$ 做一次再对 $B$ 做一次。可以只对 $A$ 做一次 DP,方法是把 DP 的第三维改成前 $i$ 个数字造成的差值模 $11$ 等于 $k$。如此定义 DP 状态,最后答案就是 $f[9][floor{N/2}][0]$。下面的 DP 也可以如此改造。

    考虑只有一个数字出现了至少 $10$ 次的情形。设此数字是 $d$。设 $d$ 在 $A$ 中出现了 $d_A$ 次,在 $B$ 中出现了 $d_B$ 次。

    可以证明任意操作序列 $(a_1, b_1), dots, (a_n, b_n)$ 都可以化成等价的操作序列 $(a'_1, b'_1), dots, (a'_k, b'_k)$ 且满足对于任意 $1 le i, j le k$,$a'_i e b'_j$。

    由于一定存在 $d$ 只作为 $a_i$ 或只作为 $b_i$ 的操作序列,我们只需考虑长度不超过 $t = max{N_A - d_A, N_B - d_B}$ 的操作序列。于是我们可以将 $A$、$B$ 中 $1$ 到 $9$ 的每个数字取出至多 $t$ 个,对这两组数目较少的数字进行 DP。

    int main() {
     int T;
     scan(T);
     rep (T) {
       kase();
       vi a(10);
       up (i, 1, 9) scan(a[i]);
       int n10 = 0; //出现次数大于等于10的数字的个数
       up (i, 1, 9) {
         n10 += a[i] >= 10;
       }
       if (n10 >= 2) {
         println("YES");
         continue;
       }
       ll n = accumulate(all(a), 0LL);
       ll m = n / 2;
       vi b(10);
       // 先随机分配,再通过DP判断能否进行调整。
       up (i, 1, 9) {
         if (a[i] < m) {
           swap(a[i], b[i]);
           m -= b[i];
         } else {
           b[i] = (int)m;
           a[i] -= (int)m;
           break;
         }
       }
    
       ll sa = 0, sb = 0;
       up (i, 1, 9) {
         sa += a[i] * i;
         sb += b[i] * i;
       }
       ll r = (sa - sb) % 11;
       if (r == 0) {
         println("YES");
         continue;
       }
       if (r < 0) {
         r += 11;
       }
       // r = r / 2;
       // (11 + 1) / 2 是 2 在模 11 下的拟元。
       r = r * (11 + 1) / 2 % 11;
       // dp[i][j][k] 在前i种数里选择j个数余数是否可能是k
       // 用滚动数组去掉dp数组第一维。
       int na = 0, nb = 0;
    
       up (i, 1, 9) {
         if (a[i] < 10) {
           na += a[i];
         }
         if (b[i] < 10) {
           nb += b[i];
         }
       }
       auto t = max(na, nb);
       up (i, 1, 9) {
         a[i] = min(a[i], t);
         b[i] = min(b[i], t);
       }
       na = accumulate(all(a), 0);
       nb = accumulate(all(b), 0);
       vv<int> A(na + 1, vi(11));
       vv<int> B(nb + 1, vi(11));
       A[0][0] = 1;
       B[0][0] = 1;
    
       int ca = 0, cb = 0;
    
       up (i, 1, 9) {
         if (a[i] > 0) {
           down (j, ca, 0) {
             rng (k, 0, 11) {
               if (A[j][k]) {
                 up (l, 1, a[i]) {
                   A[j + l][(k + l * i) % 11] = true;
                 }
               }
             }
           }
           ca += a[i];
         }
         if (b[i] > 0) {
           down (j, cb, 0) {
             rng (k, 0, 11) {
               if (B[j][k]) {
                 up (l, 1, b[i]) {
                   B[j + l][(k + l * i) % 11] = true;
                 }
               }
             }
           }
           cb += b[i];
         }
       }
    
       bool flag = false;
       up (i, 1, min(na, nb)) {
         rng (j, 0, 11) {
           if (B[i][j] && A[i][(j + r) % 11]) {
             flag = true;
             break;
           }
         }
         if (flag) break;
       }
       println(flag ? "YES" : "NO");
     }
      return 0;
    }
    
  • 相关阅读:
    win10安装mongodb教程及其失败解决方案
    基于TypeScript的NodeJs框架:NestJs开发博客API (node.js+nest.js)
    Webpack性能改造之CDN
    44道JavaScript送命题
    electron-vue学习手册
    万字长文带你深度解锁Webpack(进阶篇)
    4W字长文带你深度解锁Webpack系列(上)
    devexpress GalleryControl 获得选中的item并删除
    c# 任意角度旋转图片
    .net core3.1连接GBase数据库的步骤
  • 原文地址:https://www.cnblogs.com/Patt/p/11889930.html
Copyright © 2011-2022 走看看