记忆化搜索+容斥原理——CF div4 G. Hits Different

传送门:Problem - G - Codeforces

思路:

题意大概说的就是给定一个数字金字塔,求出指定数字在金字塔当中头顶上面的所有与它相关的数字的平方之和加上它自身的平方和。

暴力思路:

首先给定的每一个数字骑士都是可以直接计算出他在金字塔当中的位置,比如9=1+2+3+3   ,每一个数字X=1+2+3+...+t ,这里有多少个数字就说明在第几层,最后一个数字t说明在第几列,所以这里可以想到先去预处理出每一个数字的对应坐标,和每一个坐标对应的数字。

 int cnt = 0;
  for (int i = 1; i <= 2000; i++) {
    for (int j = 1; j <= i; j++) {
      ++cnt;
      f[i][j] = cnt;
      d[cnt] = {i, j};
      if (cnt == 1000000) break;
    }
    if (cnt == 1000000) break;
  }

然后每给出一个数字都是要不断向上搜索累加,用到这一条公式;

a[{x,y}]={x,y}*{x,y}+a[{x-1,y-1}]+a[{x-1,y}]-a[{x-2,y-1}]

这里利用到了容斥原理,在求9时需要加上5和6的值再减去3的值,那样才不会重复计算。

记忆化搜索优化:

这里可以选择预处理出每一个数字的答案,在算的时候会有很多数字是重复出现的,所以可以记录他们的答案,这样就可以达到O(1e6)的时间复杂度,及每个数字都只会计算一次

代码实现:

// Problem: G. Hits Different
// Contest: Codeforces - Codeforces Round 871 (Div. 4)
// URL: https://codeforces.com/contest/1829/problem/G
// Memory Limit: 256 MB
// Time Limit: 2500 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define int unsigned long long
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 10, mod = 1e9 + 7;
int a[N];
int f[2010][2010];
PII d[1000010];
int n, t, s, m;
void dfs(int x, int y) {
  if (y > x || x <= 0 || y <= 0) return;
  if (a[f[x][y]]) return;
  int res = f[x][y] * f[x][y];

  dfs(x - 1, y - 1);
  dfs(x - 1, y);
  a[f[x][y]] = res + a[f[x - 1][y - 1]] + a[f[x - 1][y]];
  if (f[x - 2][y - 1]) a[f[x][y]] -= a[f[x - 2][y - 1]];
}
signed main() {
  int cnt = 0;
  for (int i = 1; i <= 2000; i++) {
    for (int j = 1; j <= i; j++) {
      ++cnt;
      f[i][j] = cnt;
      d[cnt] = {i, j};
      if (cnt == 1000000) break;
    }
    if (cnt == 1000000) break;
  }

  for (int i = 1000000; i >= 1; i--) {
    if (a[i] == 0) {
      dfs(d[i].first, d[i].second);
    }
  }

  scanf("%lld", &t);
  while (t--) {
    int x;
    scanf("%lld", &x);
    printf("%lld\n", a[x]);
  }
  return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_62327332/article/details/130546779