HihoCoder - 1629 Graph (回滚莫队+并查集按秩合并)

题目:https://vjudge.net/contest/419697#problem/C

 

遇到了回滚莫队。

https://blog.csdn.net/a54665sdgf/article/details/82501086

开拓了眼界。

并查集随机删除是不行的,但是可以按顺序撤销,回滚莫队恰好可以支持这种操作。

 

 

[hihocoder 1635] Colored Nodes(思维+基环树)

https://blog.csdn.net/alan_cty/article/details/78713865

发现,虽然一轮之后,每个点的颜色不知道,但是知道这个点的颜色是从哪个点继承的

然后继承关系是一个基环树

只有环上的颜色最后F[i]值不为0

且环上每个颜色最后答案一样。

然后做一下就行

关键在于发现:颜色不知道,但是知道这个点的颜色是从哪个点继承的,然后转化为基环树问题。

 

 

D - Rikka with Subsequences

 ICPC昆明区域赛·赛前挣扎复习题

 https://blog.csdn.net/wxh010910/article/details/84950709

 (全网仅有的wxh的题解。。。。)

cnt^3怎么处理?

套路:用组合意义拆开。

问题转化成为,三个相同的串,从每个串中分别选出一个子序列,这三个子序列相同的方案数。(方案不一样,当且仅当存在从某个串中选出来的子序列的位置不一样)

但是还是很不好写。。。因为涉及到邻接矩阵的限制的问题。

(此处省略理解代码1.5h)

统计i,j,k位置结尾的合法子序列,必须要考虑上一个是不是能接上去,但是复杂度太高不能再枚举了。

所以先固定i,就知道了a[i],也就是b[j],c[k]必须等于a[i],否则没有意义。

很自然地设sum[j][k]表示,所有a中选<i的,b中选<j的,c中选<k的,且能直接拼在a[i]后面的三个位置作为结尾的合法子序列的方案数(显然这三个位置的字符相同)。

到了一个新的i,那么sum就必须全部重新维护(因为a[i]变了),

而sum[j][k]必然包含了从第二个串选1,2,...j-1的,第三个串选1,2,...,k-1位置的,按照二维前缀和的思想,sum[j][k]=sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1]+val

考虑val是什么

就是以所有(<i,j-1,k-1)结尾的且能拼到i后面的子序列的方案数(要保证三个位置字符相同)

设这个东西为dp[j][k](i维省了),那么dp[j][k]可以在之前几轮i的时候,枚举到a[i]==b[j]==c[k]的(i,j,k)的时候更新到

只要我们先更新sum,再求i层的贡献,再更新dp[j][k]就行了。

代码(from:wxh)

#include <bits/stdc++.h>

using namespace std;

const int N = 234;
const int md = 1e9 + 7;

int n, a[N], dp[N][N], sum[N][N];
char board[N][N];

inline void add(int &x, int y) {
  x += y;
  if (x >= md) {
    x -= md;
  }
}

inline void sub(int &x, int y) {
  x -= y;
  if (x < 0) {
    x += md;
  }
}

int main() {
  int tt;
  scanf("%d", &tt);
  while (tt--) {
    scanf("%d", &n);
    for (int i = 0; i < n; ++i) {
      scanf("%d", &a[i]);
      --a[i];
    }
    for (int i = 0; i < n; ++i) {
      scanf("%s", board[i]);
    }
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        dp[i][j] = 0;
      }
    }
    int answer = 0;
    for (int i = 0; i < n; ++i) {
      for (int j = 0; j < n; ++j) {
        for (int k = 0; k < n; ++k) {
          sum[j + 1][k + 1] = board[a[j]][a[i]] == '1' ? dp[j][k] : 0;
          add(sum[j + 1][k + 1], sum[j + 1][k]);
          add(sum[j + 1][k + 1], sum[j][k + 1]);
          sub(sum[j + 1][k + 1], sum[j][k]);
        }
      }
      for (int j = 0; j < n; ++j) {
        for (int k = 0; k < n; ++k) {
          if (a[i] == a[j] && a[i] == a[k]) {
            int ways = 1;
            add(ways, sum[j][k]);
            add(answer, ways);
            add(dp[j][k], ways);
          }
        }
      }
    }
    printf("%d\n", answer);
  }
  return 0;
}
View Code

相关文章:

  • 2021-08-17
  • 2022-12-23
  • 2022-01-18
  • 2021-12-03
  • 2021-12-17
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-02-13
相关资源
相似解决方案