题意:给你一个n位”数“(前导0也算数字),问小于它的数字有多少,其中小于号重载为:
1.a各个位上的数字和小于b.
2.1相等的前提下a各个位上的数字+1相乘小于b.
3.1,2相等的前提下a的十进制意义小于b。
分析:真.乱搞题,第一个条件可以数位DP,第二个条件按顺序搜索,第三种情况直接在第二种基础上统计。
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<cmath>
#include<queue>
#include <unordered_map>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MOD 7340033
using namespace std;
typedef long long ll;
char s[17];
int n,num[10];
ll dp[17][160],a[17],b[17],f[20],Ans,pre,pre2;
ll dfs(int pos,int pre)
{
if(pos == -1) return 1ll;
if(dp[pos][pre] >= 0) return dp[pos][pre];
ll ans = 0;
for(int i = 0;i <= 9;i++)
if(pre > i) ans += dfs(pos-1,pre - i);
dp[pos][pre] = ans;
return ans;
}
ll solve(char s[])
{
int pos = 0;
pre = 0;
for(int i = 0;i < n;i++)
{
a[i] = s[n-i-1] - '0';
pre += a[i];
}
memset(dp,-1,sizeof(dp));
return dfs(n-1,pre);
}
void dfs2(int pos,int up,int res,ll sta)
{
if(pos == -1)
{
ll ans = 0;
if(res == 0 && sta == pre2)
{
int Num[10];
for(int i = 0;i <= 9;i++) Num[i] = num[i];
for(int i = n;i;i--)
{
for(int j = 0;j < a[i-1];j++)
if(Num[j])
{
ans = f[i-1]*Num[j];
for(int k = 0;k <= 9;k++) ans/= f[Num[k]];
Ans += ans;
}
if(Num[a[i-1]]) Num[a[i-1]]--;
else break;
}
}
if(res == 0 && sta < pre2)
{
ans = f[n];
for(int i = 0;i <= 9;i++) ans /= f[num[i]];
Ans += ans;
}
return;
}
for(int i = up;i >= 0;i--)
if(res >= i && (i+1)*sta <= pre2)
{
num[i]++;
dfs2(pos-1,i,res-i,sta*(i+1));
num[i]--;
}
}
int main()
{
f[0] = 1ll;
for(int i = 1;i <= 16;i++) f[i] = f[i-1] * i;
while(~scanf("%s",s))
{
n = strlen(s);
Ans = solve(s);
pre2 = 1ll;
for(int i = 0;i < n;i++) pre2 *= (a[i]+1);
memset(num,0,sizeof(num));
dfs2(n-1,9,pre,1ll);
cout<<Ans<<endl;
}
}