1 条题解

  • 0
    @ 2025-8-24 22:49:10

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 22:49:10,当前版本为作者最后更新于2023-09-17 14:46:44,作者可能在搬运后再次修改,您可在原文处查看最新版

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

    以下是正文


    P9522 [JOISC2022] 错误拼写

    考虑 TiTjT_{i}\leq T_{j} 的等价条件。模拟字典序比较的过程:

    • i<ji < j,那么要么 sijs_{i\sim j} 全部相等,要么 si>sps_i > s_p,其中 pp 是从 ii 开始第一个不等于 sis_i 的位置。
    • i>ji > j,那么要么 sjis_{j\sim i} 全部相等,要么 sj<sps_j < s_p,其中 pp 是从 jj 开始第一个不等于 sjs_j 的位置。

    考虑从后往前 DP,设 fi,jf_{i, j} 表示 si=js_i = j 的方案数。计算 fi,jf_{i, j} 时,枚举 ii' 表示 sii1s_{i\sim i' - 1} 相等且 si1sis_{i' - 1}\neq s_{i'},枚举 jjj'\neq j。考虑什么情况下 fi,jf_{i, j} 可以从 fi,jf_{i', j'} 转移过来:如果存在 iu<ivi\leq u < i' \leq v 要求 TuTvT_u\leq T_v,那么 jj 不能小于 jj';若要求 TuTvT_u\geq T_v,那么 jj 不能大于 jj'

    u<vu < v,则:

    • 当有限制 TuTvT_u\leq T_v 时,在 u<ivu < i'\leq v 转移到 uu 之前的位置时,必须有 j>jj > j'

    • 当有限制 TuTvT_u\geq T_v 时,在 u<ivu < i'\leq v 转移到 uu 之前的位置时,必须有 j<jj < j'

    这说明,固定了 ii' 之后,随着 ii 不断向前移动,存在一个时刻使得 ii' 不再能产生 j>jj > j' 的贡献,也存在一个时刻使得 ii' 不再能产生 j<jj < j' 的贡献。

    hjh_j 表示 fi+1fnf_{i + 1}\sim f_n 对之前的位置的每个 jj 产生的贡献。枚举到 ii 时,考虑所有和 ii 有关的限制 (u,v)(u, v)u=i<vu = i < v

    • 若限制 TuTvT_u\leq T_v,那么对于所有 u<ivu < i'\leq v 且仍产生 j<jj < j' 的贡献的 ii',将它 j<jj < j' 的贡献从 hh 中去掉,即令 hjh_j 减去 j<jfi,j\sum_{j < j'} f_{i', j'}
    • 若限制 TuTvT_u\geq T_v,那么对于所有 u<ivu < i' \leq v 且仍产生 j>jj > j' 的贡献的 ii',将它 j>jj > j' 的贡献从 hh 中去掉,即令 hjh_j 减去 j>jfi,j\sum_{j > j'} f_{i', j'}

    更新 hh 之后有 fi,j=hj+1f_{i, j} = h_j + 1,其中 11 表示 sins_{i\sim n} 均相等的情况。统计 fif_ihh 的贡献:hjh_{j} 加上 jjfi,j\sum_{j'\neq j} f_{i, j'}

    用链表或栈维护两种情况仍产生贡献的 ii',时间复杂度 O(nΣ)\mathcal{O}(n|\Sigma|)

    #include <bits/stdc++.h>
    using namespace std;
    
    using ll = long long;
    using LL = __int128_t;
    using ui = unsigned int;
    using ull = unsigned long long;
    using pii = pair<int, int>;
    using pll = pair<ll, ll>;
    using pdi = pair<double, int>;
    
    #define ppc(x) __builtin_popcount(x)
    #define clz(x) __builtin_clz(x)
    
    bool Mbe;
    // mt19937 rnd(chrono::steady_clock::now().time_since_epoch().count());
    mt19937 rnd(20060130);
    int rd(int l, int r) {return rnd() % (r - l + 1) + l;}
    
    constexpr int mod = 1e9 + 7;
    void addt(int &x, int y) {x += y, x >= mod && (x -= mod);}
    int add(int x, int y) {return x += y, x >= mod && (x -= mod), x;}
    
    char buf[1 << 20], *p1 = buf, *p2 = buf;
    #define getc() (p1 == p2 && (p2 = (p1 = buf) + \
      fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
    inline int read() {
      int x = 0;
      char s = getc();
      while(!isdigit(s)) s = getc();
      while(isdigit(s)) x = x * 10 + s - '0', s = getc();
      return x;
    }
    
    #define putc(x) putchar(x)
    inline void print(ui x) {
      if(x >= 10) print(x / 10);
      putc(x % 10 + '0');
    }
    
    // ---------- templates above ----------
    
    constexpr int N = 5e5 + 5;
    
    int n, m, f[N][27], h[27];
    int a[N], b[N], x[N], y[N];
    vector<int> e[N], g[N];
    
    void mian() {
      cin >> n >> m;
      for(int i = 1; i <= n; i++) a[i] = b[i] = i + 1;
      for(int i = 1; i <= m; i++) {
        int x, y;
        cin >> x >> y;
        if(x < y) e[x].push_back(y);
        else g[y].push_back(x);
      }
      for(int i = n; i; i--) {
        for(int it : e[i]) {
          for(int p = a[i]; p <= it; p = a[p]) {
            vector<int> s(27);
            for(int j = 1; j <= 26; j++) s[j] = add(s[j - 1], f[p][j]);
            for(int j = 1; j <= 26; j++) addt(h[j], mod - add(s[26], mod - s[j]));
            a[i] = a[p];
          }
        }
        for(int it : g[i]) {
          for(int p = b[i]; p <= it; p = b[p]) {
            vector<int> s(27);
            for(int j = 1; j <= 26; j++) s[j] = add(s[j - 1], f[p][j]);
            for(int j = 1; j <= 26; j++) addt(h[j], mod - s[j - 1]);
            b[i] = b[p];
          }
        }
        int sum = 0;
        for(int j = 1; j <= 26; j++) {
          f[i][j] = h[j] + 1;
          addt(h[j], mod - f[i][j]);
          addt(sum, f[i][j]);
        }
        if(i == 1) cout << sum << "\n";
        for(int j = 1; j <= 26; j++) addt(h[j], sum);
      }
    }
    
    bool Med;
    int main() {
      fprintf(stderr, "%.3lf MB\n", (&Mbe - &Med) / 1048576.0);
      ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
      #ifdef ALEX_WEI
        FILE* IN = freopen("1.in", "r", stdin); 
        FILE* OUT = freopen("1.out", "w", stdout);
      #endif
      int T = 1;
      while(T--) mian();
      fprintf(stderr, "%d ms\n", int(1e3 * clock() / CLOCKS_PER_SEC));
      return 0;
    }
    
    /*
    g++ a.cpp -o a -std=c++14 -O2 -DALEX_WEI
    */
    
    • 1

    信息

    ID
    9070
    时间
    3500ms
    内存
    1024MiB
    难度
    6
    标签
    递交数
    0
    已通过
    0
    上传者