HAOI2010 计数 【动态规划】

我的心路历程:当你觉得一题是傻逼题,没想出来,就觉得是神仙题,看题解后又发现题解说这题是傻逼题,写完后发现这题真的是傻逼题

我们可以发现,对于在n前面的数,每个数字(包括0,因为把0删掉就相当把它变成前导0)出现的次数都是一样,那么题目就变成了:问在这些数字组成的全排列中,在n前面的有多少

直接数位dp,只要有任意以为的数字是小于n的对应数字的,后面的就随便填,相当于全排列

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#define gi get_int()
#define int long long
const int MAXN = 1001;
int get_int()
{
  int x = 0, y = 1;
  char ch = getchar();
  while (!isdigit(ch) && ch != '-')
    ch = getchar();
  if (ch == '-')
    y = -1, ch = getchar();
  while (isdigit(ch))
    x = x * 10 + ch - '0', ch = getchar();
  return x * y;
}

int num[MAXN], C[MAXN][MAXN], count[MAXN];

signed main()
{
  std::string str;
  std::cin >> str;
  int n = str.size();
  for (int i = 0; i < str.size(); i++) {
    num[i] = str[i] - '0';
    count[str[i] - '0']++;
  }
  int ans = 0;
  for (int i = 0; i <= n; i++)
    C[i][0] = 1;
  for (int i = 1; i <= n; i++)
    for (int j = 1; j <= i; j++)
      C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < num[i]; j++) {
      count[j]--;
      int tot = n - i - 1, tmp = 1;
      for (int k = 0; k < 10; k++) {
        tmp *= C[tot][count[k]];
        tot -= count[k];
      }
      ans += tmp;
      count[j]++;
    }
    count[num[i]]--;
  }
  std::cout << ans;

  return 0;
}
posted @ 2021-05-24 17:25  enisp  阅读(51)  评论(0)    收藏  举报