1 条题解

  • 0
    @ 2025-8-24 22:54:04

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Phartial
    **

    搬运于2025-08-24 22:54:04,当前版本为作者最后更新于2023-12-31 20:51:25,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    P10034 「Cfz Round 3」Circle 题解

    对于一个排列 pp,我们连边 ipii\to p_i,则其构成了若干个环。fp,k(i)f_{p,k}(i) 的含义即为:从 ii 开始走 kk 步到达的点。

    题目限制可以等价描述为:使所有满足 Si=1S_i=\texttt{1} 的点都位于一个大小为 ll 的因数的环上。

    注意到如果存在方案,则必然存在一种使所有环的大小都为质数的方案(否则我们就可以把其中大小不是质数的环拆成若干个大小为质数的环而不影响合法性)。

    考虑把 ll 的所有 n\le n 的质因数弄出来,其最多只有 1515 个。环的大小只可能是这几种。

    观察一下最终方案长啥样:其有 kk 个节点在大小为 ll 的质因数的环上,nkn-k 个节点单独成一环(这些节点中不应有 Si=1S_i=\texttt{1} 的点),有约束条件 ckn,kn1c\le k\le n,k\ne n-1(其中 ccSS1\texttt{1} 的数量)。

    跑一遍完全背包即可判断可行性并得到一个可行的 kk,记录一下转移路径即可还原出方案。

    需要特判 l=0l=0,代码有点难写。

    #include <iostream>
    #include <vector>
    
    using namespace std;
    using LL = long long;
    
    const int kN = 5e5 + 1, kC = 16;
    
    int tt, n, ans[kN], d[kN], id[kN], c;
    bool f[kC][kN], p[kC][kN], ip[kN];
    vector<int> tp, pl;
    string s;
    LL l;
    
    bool S() {
      pl.assign(1, 0);
      for (int i : tp) {
        if (i > n) {
          break;
        }
        if (l % i == 0) {
          pl.push_back(i);
        }
      }
      int m = pl.size() - 1;
      f[0][0] = 1;
      for (int i = 1; i <= m; ++i) {
        for (int j = 0; j <= n; ++j) {
          f[i][j] = 0;
          if (f[i - 1][j]) {
            f[i][j] = 1, p[i][j] = 0;
          } else if (j >= pl[i] && f[i][j - pl[i]]) {
            f[i][j] = 1, p[i][j] = 1;
          }
        }
      }
      int k = c;
      for (; k <= n && (k == n - 1 || !f[m][k]); ++k) {
      }
      if (k > n) {
        return 0;
      }
      int x = 1;
      for (int i = m; i >= 1; --i) {
        for (; p[i][k]; k -= pl[i]) {
          int _x = x;
          for (int j = pl[i] - 1; j--; ++x) {
            ans[x] = x + 1;
          }
          ans[x++] = _x;
        }
      }
      if (x < n) {
        ans[n] = x;
        for (; x < n; ++x) {
          ans[x] = x + 1;
        }
      }
      return 1;
    }
    
    int main() {
      ios_base::sync_with_stdio(0), cin.tie(0);
      for (int i = 2; i < kN; ++i) {
        if (!ip[i]) {
          tp.push_back(i);
        }
        for (int j : tp) {
          int k = i * j;
          if (k >= kN) {
            break;
          }
          ip[k] = 1;
          if (i % j == 0) {
            break;
          }
        }
      }
      for (cin >> tt; tt--;) {
        cin >> n >> l >> s;
        s = "#" + s;
        int m = 0;
        for (int i = 1; i <= n; ++i) {
          if (s[i] == '1') {
            id[d[i] = ++m] = i;
          }
        }
        c = m;
        if (!l) {
          for (int i = 2; i <= n; ++i) {
            cout << i << ' ';
          }
          cout << 1 << '\n';
          continue;
        }
        for (int i = 1; i <= n; ++i) {
          if (s[i] == '0') {
            id[d[i] = ++m] = i;
          }
        }
        if (S()) {
          for (int i = 1; i <= n; ++i) {
            cout << id[ans[d[i]]] << ' ';
          }
        } else {
          cout << -1;
        }
        cout << '\n';
      }
      return 0;
    }
    
    • 1