mxqz 样例过了但是只有 65 分啊啊啊
查看原帖
mxqz 样例过了但是只有 65 分啊啊啊
176843
LiveZoom楼主2022/11/27 19:36
#include <cstdio>
#include <ctime>
#include <iostream>
#include <vector>
#include <stack>
#include <map>
#include <utility>

#define int long long

using namespace std;

const int kMaxN = 1e6 + 5, kMaxM = 1e6 + 5, kMod = 1e9 + 7;

int n, m, cnt, tot;
int u[kMaxM], v[kMaxM], pw[kMaxN];
int sz[kMaxN], dfn[kMaxN], low[kMaxN], dcc[kMaxN];
int sum[kMaxN], f[kMaxN][5], pre[kMaxN], suf[kMaxN], id[kMaxN], s[3];
vector<int> g[kMaxN], G[kMaxN];
stack<int> stk;
map<pair<int, int>, bool> mp;

int mod(int x) {
  return (x % kMod + kMod) % kMod;
}

void addE(int u, int v) {
  g[u].emplace_back(v);
}

void tarjan(int u, int fa) {
  dfn[u] = low[u] = ++cnt;
  stk.emplace(u);
  for (auto v : g[u]) {
    if (!dfn[v]) {
      tarjan(v, u);
      low[u] = min(low[u], low[v]);
    } else if (v != fa) {
      low[u] = min(low[u], dfn[v]);
    }
  }
  if (low[u] == dfn[u]) {
    ++tot;
    while (!stk.empty()) {
      int nt = stk.top();
      stk.pop();
      ++sz[tot], dcc[nt] = tot;
      if (nt == u) break;
    }
  }
}

void dfs(int u, int fa) {
/* 
  f[i][0] : i 的子树内,一个都不选的答案
  f[i][1] : i 的子树内,i 选,子树中都不选
  f[i][2] : i 的子树内,i 选,子树中选至少 1 个
  f[i][3] : i 的子树中,i 不选,子树中选至少 1 个,子树外没有点
  f[i][4] : i 的子树中,i 不选,子树中选至少 1 个,子树外有点
*/
  int t, tmp;
  if (u == 1) t = G[u].size();
  else t = G[u].size() - 1;
  if (!t) {
    f[u][0] = 1, f[u][1] = pw[sz[u]] - 1;
    return;
  }
  t = 0;
  f[u][0] = f[u][3] = f[u][4] = 1;
  f[u][1] = f[u][2] = tmp = pw[sz[u]] - 1;
  // solve f[u][0/1/2]
  for (auto v : G[u]) {
    if (v == fa) continue ;
    dfs(v, u);
    f[u][0] = 2ll * f[u][0] * f[v][0] % kMod;
    f[u][1] = 2ll * f[u][1] * f[v][0] % kMod;
    f[u][2] = 1ll * f[u][2] * (2ll * f[v][0] + f[v][1] + f[v][2] + f[v][4]) % kMod;
    id[++t] = v;
  }
  f[u][2] = mod(f[u][2] - f[u][1]);
  // solve f[u][3]
  pre[0] = suf[t + 1] = 1;
  // 1. 子树中只有一个选
  for (int i = 1; i <= t; ++i) pre[i] = 2ll * pre[i - 1] * f[id[i]][0] % kMod;
  for (int i = t; i; --i) suf[i] = 2ll * suf[i + 1] * f[id[i]][0] % kMod;
  f[u][3] = 0;
  for (int i = 1; i <= t; ++i) {
    int v = id[i];
    f[u][3] = (f[u][3] + 2ll * pre[i - 1] * suf[i + 1] % kMod *
               mod(f[v][1] + f[v][2] + f[v][3]) % kMod) % kMod;
  }
  // 2. 子树中有至少两个选
  s[0] = 1, s[1] = s[2] = 0;
  for (int i = 1; i <= t; ++i) {
    int v = id[i];
    s[2] = (1ll * s[2] * mod(2ll * f[v][0] % kMod + f[v][1] + f[v][2] + f[v][4])
         % kMod + 1ll * s[1] * (f[v][1] + f[v][2] + f[v][4]) % kMod) % kMod;
    s[1] = (2ll * s[1] * f[v][0] % kMod + 1ll * s[0] * (f[v][1] + f[v][2] + f[v][4]) % kMod) % kMod;
    s[0] = 2ll * s[0] * f[v][0] % kMod;
  }
  f[u][3] = (f[u][3] + s[2]) % kMod;

  // solve f[u][4]
  tmp = 1;
  for (int i = 1; i <= t; ++i) {
    int v = id[i];
    f[u][4] = 1ll * f[u][4] * (2ll * f[v][0] + f[v][1] + f[v][2] + f[v][4]) % kMod;
    tmp = 2ll * tmp * f[v][0] % kMod;
  }
  f[u][4] = mod(f[u][4] - tmp);
}

signed main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for (int i = 1; i <= m; ++i) {
    cin >> u[i] >> v[i];
    addE(u[i], v[i]), addE(v[i], u[i]);
  }
  for (int i = 1; i <= n; ++i)
    if (!dfn[i])
      tarjan(i, 0);
  for (int i = 1; i <= m; ++i) {
    int x = dcc[u[i]], y = dcc[v[i]];
    if (x > y) swap(x, y);
    if (x == y || mp[{x, y}]) continue;
    mp[{x, y}] = 1;
    G[x].emplace_back(y);
    G[y].emplace_back(x);
  }
  pw[0] = 1ll;
  for (int i = 1; i <= max(n, m); ++i)
    pw[i] = 2ll * pw[i - 1] % kMod;
  dfs(1, 0);
  cerr << tot << '\n';
  // cerr << f[1][3] << '\n';
  cout << 1ll * mod(f[1][1] + f[1][2] + f[1][3]) * pw[m - (tot - 1)] % kMod << '\n';
  cerr << 1.0 * clock() / CLOCKS_PER_SEC << 's' << '\n';
  return 0;
}
2022/11/27 19:36
加载中...