test1

P7293 Sum of Distances P

首先注意一个点不能不动,那么假如一个点 \((a_1, a_2 \dots a_k) \to (b_1, b_2 \dots b_k)\),相当于 \(a_1 \to b_1, a_2 \to b_2 \dots a_k \to b_k\)\(k\) 个点分别走。那么如果走最短路,快的就可以通过走某一条邻边并反复横跳等待慢的。但是假如有两个点奇偶性不同,就必须走一个奇环来更改最短路的奇偶性。那么相当于要求 \(\forall i, dis_i = dis (a_i \to b_i)\) 的奇偶性都相同。

那么跑出每个点 \(i\)\(1\) 的奇偶最短路 \(dis_{i, 0 /1}\),那么对于一个选择方案 \((a_1, a_2 \dots a_k)\),则需要的最短步数是 \(\min({\max_{i = 1}^n dis_{i, 0}}, \max_{i = 1}^n dis_{i, 1})\)。可以直接 \(\rm DP\) 做到 \(O(n^3) / O(n^4)\)

考虑这个转化:\(\min(a, b) = a + b - \max(a, b)\),若 \(a, b\) 是形如 \(\max_{i = 1} ^n x_i\) 的柿子,那么这个东西就可以转化为 \(3\) 个子问题。于是设 \(f_{i, j}\) 为考虑前 \(i\) 个图,\(\max = j\) 的方案数,然后按 \(m_i\) 排序后的顺序 \(\rm DP\) 可以保证第二维的和为 \(O(n)\),前缀和优化就可以 \(O(n)\),使用滚动数组可以做到空间复杂度 \(O(n)\)。于是 \(O(n \log n) / O(n)\) 即可完成。

代码没有排序,但是过了。

qwq
#include<bits/stdc++.h>
#define ll long long
#define pb emplace_back
#define pir pair<int, ll>
#define fi first
#define se second
#define inv(x) qpow(x, mod - 2)
#define il inline
#define mkpir make_pair
using namespace std;

const int N = 4e5 + 10, M = 2e5 + 10;
const ll mod = 1e9 + 7;

il ll qpow(ll& x, ll y){
  ll ret = 1;
  for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
  return ret;
}
il void chkmin(ll& x, ll y){if(y < x) x = y;}
il void chkmin(int& x, int y){if(y < x) x = y;}
il void chkmax(int& x, int y){if(y > x) x = y;}
il void chkmax(ll& x, ll y){if(y > x) x = y;}
il void ADD(ll& x, ll y){x += y; (x >= mod) ? (x -= mod) : 0;}
il void MUL(ll& x, ll y){x = x * y % mod;}

int k, st[N], dis[N][2], n, mx[N], len[N];
struct edge{
  int v, next;
}edges[N << 1];
int head[N], idx;

void add_edge(int u, int v){
  edges[++idx] = {v, head[u]};
  head[u] = idx;
}

void bfs(int s){
  queue<pir> Q; dis[s][0] = 0; Q.push(mkpir(s, 0));
  while(!Q.empty()){
    int u = Q.front().first, op = Q.front().second; Q.pop();
    for(int i = head[u]; i; i = edges[i].next){
      int v = edges[i].v;
      if(dis[v][op ^ 1] > dis[u][op] + 1) dis[v][op ^ 1] = dis[u][op] + 1, Q.push(mkpir(v, op ^ 1));
    }
  }
}

struct DP{
  int lim;
  ll f[N], g[N], s[N], dif[N];
  void init(){f[0] = 1;}
  void cpy(int V){
    //cerr << V << "\n";
    for(int i = 0; i <= lim; i++) ADD(dif[i], i ? dif[i - 1] : 0ll), MUL(g[i], dif[i]), ADD(f[i], g[i]);//, cerr << i << " " << dif[i] << " " << g[i] << " " << f[i] << "\n";
    s[0] = g[0] = f[0]; f[0] = 0; chkmax(lim, V);
    for(int i = 1; i <= lim; i++) dif[i] = 0, s[i] = (s[i - 1] + f[i]) % mod, g[i] = f[i], f[i] = 0;//, cerr << i << " " << dif[i] << " " << g[i] << " " << f[i] << "\n";

  }
  void add(int x){
    if(x > lim) return;
    ADD(dif[x + 1], 1); ADD(f[x], s[x]); 
  }
  ll getans(){
    cpy(lim); ll ans = 0;
    for(int i = 1; i <= lim; i++) ADD(ans, i * g[i] % mod);//, cerr << g[i] << "\n";
    //cerr << lim << " " << ans << "\n";
    return ans;
  }
}d1, d2, d3;
// for y: f_{max(x, y)} += g_x
// f_y += s_y
// x > y : f_x += g_x

signed main(){
  ios::sync_with_stdio(0);
  cin.tie(0); cout.tie(0);
  cin >> k; st[0] = 1; memset(dis, 0x3f, sizeof dis); int INF = dis[0][0];
  for(int G = 1; G <= k; G++){
    //cerr << G << "\n";
    int m; cin >> len[G] >> m; st[G] = st[G - 1] + len[G - 1]; n += len[G];
    for(int i = 1; i <= m; i++){
      int x, y; cin >> x >> y; x += st[G] - 1; y += st[G] - 1; 
      add_edge(x, y); add_edge(y, x);
    } bfs(st[G]);
    for(int i = st[G]; i < st[G] + len[G]; i++){
      if(dis[i][0] < INF) chkmax(mx[G], dis[i][0]);
      if(dis[i][1] < INF) chkmax(mx[G], dis[i][1]);
      //cerr << dis[i][0] << " " << dis[i][1] << "\n";
    }
  } d1.init(); d2.init(); d3.init();
  for(int G = 1; G <= k; G++){
    d1.cpy(mx[G]); d2.cpy(mx[G]); d3.cpy(mx[G]);
    for(int i = st[G]; i < st[G] + len[G]; i++) d1.add(dis[i][0]), d2.add(dis[i][1]), d3.add(max(dis[i][1], dis[i][0]));
  } cout << ((d1.getans() + d2.getans() - d3.getans()) % mod + mod) % mod << "\n";

  return 0;
}

posted @ 2025-04-19 08:37  Little_corn  阅读(13)  评论(0)    收藏  举报