[HAOI2010] Counting

topic here

description

You have a set of non-zero numbers (not necessarily unique) into which you can insert any number of 0s, which results in an infinite number.
For example, given {1,2}, the numbers 12, 21, 102, 120, 201, 210, 1002, 1020, etc. can be generated.
Now given a number, ask how many numbers come before this number. (Note that this number will not have leading zeros).

data range

\[The length of n does not exceed 50, and the answer does not exceed 2^{63}-1.\]

solution

The problem is equivalent to finding the number of numbers less than \(n\) (including leading 0) after disassembling \(n\) bit by bit and recombining it . Consider the number \(DP\) , when from the dangerous state to the safe state, Since we already know the following numbers and can take them arbitrarily, can we just use combinatorial mathematics to count them?

Assuming that the \(i\)th bit \(a_i\) is currently considered and a number \(s\) is selected to replace this bit, and it is known that the latter part of the number is
not included in the \(i\)th bit. number, stored in \(t_{0...9}\) ,
then the answer of the current one is \[\sum_{s=0}^{a_i-1}\frac{(\sum_{k= 0}^{9}t[k])!}{\prod_{k=0}^{9}t[k]!}\]

If you write the code according to this recursion, you will get a good score of \(60\) because of the explosion \(long long\)

So the answer needs to be converted, because \[\frac{(\sum_{k=0}^{9}t[k])!}{\prod_{k=0}^{9}t[k]!}= \prod_{k=0}^{9}C_{\sum_{k=s}^{9}t[k]}^{t[s]}\]

Finally, adding each answer can
be achieved. In the process of specific implementation, there is no need to open the dynamic programming array at all.

code

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#define RG register
#define il inline
using namespace std;
typedef long long ll;
typedef double dd;
typedef vector<int> VI;
const int N=52;
ll n,a[N],t[10],tot,ans,C[N][N];
il ll calc(int x){
  RG ll sum=1,cnt=tot-1;
  for(RG int i=0;i<=9;i++)
    if(t[i]-(i==x))
      sum*=C[cnt][(t[i]-(i==x))],cnt-=(t[i]-(i==x));
  return sum;
}

int main()
{
  RG char ch=0;
  C[0][0]=1;
  for(RG int i=1;i<=50;i++)
    for(RG int j=0;j<=50;j++){
      C[i][j]=C[i-1][j];
      if(j)C[i][j]+=C[i-1][j-1];
    }
  while(ch>'9'||ch<'1')ch=getchar();
  while(ch<='9'&&ch>='0'){a[++n]=ch-48;t[a[n]]++;tot++;ch=getchar();}
  for(RG int i=1;i<=n;tot--,t[a[i]]--,i++)
    for(RG int k=0;k<a[i];k++)
      if(t[k])ans+=calc(k);
  
  printf("%lld\n",ans);
  return 0;
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325344348&siteId=291194637