[USACO06FEB] Backward Digit Sums G/S

Luogu [USACO06FEB] Backward Digit Sums G/S

为什么标签里没有数学?

这道题怎么着也有点数学吧

Yesterday

看了包括这道题的四道题,没有一道题会做,于是开颓

Today

写完作业想了想,洗了个澡,回来 \(15 \min\) 就水完了

正文部分

这道题的难点就是它不是所有的数加起来,而是像这样:
image
-抽象派画风-


观察系数:
image
同志们,这是什么
很显然,杨辉三角(即组合数)
-这就是为什么我要吐槽这道题的标签-
所以,最后得到的数(\(sum\))就是

\[\sum^n_1(a_i \cdot C^i_n) \]

并且根据题目要求,\(\forall i,j\in \text N,i,j\in [1,n],i\not=j\),都有 \(a_i \not= a_j\)

至此,我们可以进行 \(dfs\)
对于每一个位置,选取一个数,再根据上面的公式进行统计和,就可以避免繁琐的计算了
其中,统计和的时候可以实时更新
并且如果枚举到一个数乘上当前位置的组合数已经大于题目给的和了,就直接 \(break\) (但是这样好像优化不了多少)

代码

点击查看代码
#include <iostream>
#include <cstdlib>

using namespace std;
const int maxn = 15;

int n, sum;
int ans[maxn];
int vis[maxn];
int c[maxn][maxn];

void dfs(int cnt, int s)
{
  if (cnt >= n)
  {
    if (s == sum)
    {
      for (int i = 1; i <= n; ++i)
        cout << ans[i] << ' ';
      exit(0);
    }
    return ;
  }
  for (int i = 1; i <= n; ++i)
  {
    if (s + c[n][cnt + 1] * i > sum)
      break;
    if (vis[i])
      continue;
    vis[i] = 1;
    ans[cnt + 1] = i;
    dfs(cnt + 1, s + c[n][cnt + 1] * i);
    vis[i] = 0;
  }
}

int main()
{
  cin >> n >> sum;
  // 预处理组合数
  c[1][1] = 1;
  for (int i = 1; i <= 12; ++i)
  {
    c[i][1] = 1;
  }
  for (int i = 2; i <= 12; ++i)
  {
    c[i][i] = 1;
    for (int j = 2; j < i; ++j)
    {
      c[i][j] = c[i - 1][j] + c[i - 1][j - 1];
    }
  }
  // ~~~~~~~
  dfs(0, 0);
  return 0;
}

posted @ 2024-12-12 22:24  SigmaToT  阅读(10)  评论(0)    收藏  举报