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;
}

浙公网安备 33010602011771号