高维前缀和

二维前缀和是总所周知的,它长这样:

\[f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i-1][j-1] \]

这实际上是容斥原理。但我们还可以这样求 \(f\) 的前缀和:

for (int i = 1; i <= n; i++)
  for (int j = 1; j <= n; j++)
    f[i][j] += f[i][j - 1];

for (int i = 1; i <= n; i++) 
  for (int j = 1; j <= n; j++)
    f[i][j] += f[i - 1][j];

两个循环交换位置也是可以的,很容易证明。这样,我们还可以推广到三维:

for(int i = 1; i <= n; i ++)
  for(int j = 1; j <= n; j ++)
    for(int k = 1; k <= n; k ++)
      f[i][j][k] += f[i - 1][j][k];

for(int i = 1; i <= n; i ++)
  for(int j = 1; j <= n; j ++)
    for(int k = 1; k <= n; k ++)
      f[i][j][k] += f[i][j - 1][k];

for(int i = 1; i <= n; i ++)
  for(int j = 1; j <= n; j ++)
    for(int k = 1; k <= n; k ++)
      f[i][j][k] += f[i][j][k - 1];

这三个三重循环之间的顺序怎么交换都行,你可以先求j这个维度再求i这个维度最后再求k这个维度,都是等价的。\(n\) 维的同理。当每个维度都只有2个元素时,我们还可以直接状压dp。

由此我们可以引出这个题:

P5495 【模板】Dirichlet 前缀和

假设 \(x = ap_i^k\)\(y=ap_i^{k+1}\) ,其中 \(p_i\)\(x\) 的某一个质因数,则很显然 \(b_y = b_x + 1\) 。那么,这不就是在 \(p_i\) 这个维度求前缀和吗?所以我们就可以直接高维前缀和了。code:

#include <bits/stdc++.h>
using namespace std;

#define debug
#define uint unsigned int
#define N 20000010

uint n;
uint a[N], p[N], cnt;
bool not_prime[N];
uint seed;
inline uint etnext() {
  seed ^= seed << 13;
  seed ^= seed >> 17;
  seed ^= seed << 5;
  return seed;
}

void init() {
  for (int i = 2; i <= n; i++) {
    if (!not_prime[i]) {
      p[++cnt] = i;
    }
    for (int j = 1; j <= cnt; j++) {
      if (1ll * i * p[j] > 1ll * N) break;
      not_prime[i * p[j]] = 1;
      if (i % p[j] == 0)  break;
    }
  }
}

signed main() {
//   freopen("shuju.in", "r", stdin);
  ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
  cin >> n >> seed;
  init();
  for(int i = 1; i <= n; i ++){
    a[i] = etnext();
  }
  for (int i = 1; i <= cnt; i++) {
    for(int j = 1; j * p[i] <= n; j ++){
      a[p[i] * j] += a[j];
    }
  }
  uint ans = 0;
  for(int i = 1; i <= n; i ++){
    ans ^= a[i];
  }
  cout << ans;
  return 0;
}
posted @ 2024-07-30 19:33  星影流灿  阅读(51)  评论(0)    收藏  举报