[CodeChef-DGTCNT]Chef and Digits
题目大意:
若一个十进制数$x$(不含前导零)满足数码$i$恰好出现$t_i$次,则这个数是坏的,否则是好的。求区间$[L,R](1\le L,R\le10^{18})$中有多少好数。
思路:
显然可以将区间$[L,R]$拆成$[1,R],[1,L)$分别计算。考虑计算区间$[1,n]$中好数的个数,可以用类似数位DP的方法,对于长度与$n$相等的情况枚举与$n$的LCP和LCP前的数字,否则枚举长度及首位数字直接计算。当限制不存在时,显然可以通过组合数计算答案。加上限制可以用容斥来计算,极限数据时间复杂度约$O(2^{10}\cdot18\cdot10\cdot18)$。
1 #include<cstdio> 2 #include<cctype> 3 typedef long long int64; 4 inline int64 getint() { 5 register char ch; 6 while(!isdigit(ch=getchar())); 7 register int64 x=ch^'0'; 8 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); 9 return x; 10 } 11 const int B=10,M=19; 12 int t[B],tmp[B],dig[M],spc[B]; 13 int64 C[M][M],pow[B+1][M]; 14 inline int64 calc(int l) { 15 int64 ret=1; 16 for(register int i=1;i<=spc[0]&&l>=0;i++) { 17 if(tmp[spc[i]]<0) return 0; 18 ret*=C[l][tmp[spc[i]]]; 19 l-=tmp[spc[i]]; 20 } 21 ret*=pow[10-spc[0]][l]; 22 return ret; 23 } 24 inline int64 count() { 25 int64 ret=0; 26 for(register int i=0;i<B;i++) tmp[i]=t[i]; 27 for(register int i=1;i<=dig[0]-1;i++) { 28 for(register int j=1;j<B;j++) { 29 tmp[j]--; 30 ret+=calc(i-1); 31 tmp[j]++; 32 } 33 } 34 for(register int i=dig[0];i;i--) { 35 for(register int j=i==dig[0];j<dig[i];j++) { 36 tmp[j]--; 37 ret+=calc(i-1); 38 tmp[j]++; 39 } 40 tmp[dig[i]]--; 41 } 42 ret+=calc(0); 43 return ret; 44 } 45 inline int64 solve(int64 n) { 46 if(!n) return 0; 47 for(dig[0]=0;n;n/=10) dig[++dig[0]]=n%10; 48 int64 ret=0; 49 for(register int i=0;i<1<<B;i++) { 50 for(register int j=spc[0]=0;j<B;j++) { 51 if((i>>j)&1) spc[++spc[0]]=j; 52 } 53 ret+=(__builtin_popcount(i)&1?-1:1)*count(); 54 } 55 return ret; 56 } 57 inline void init() { 58 for(register int i=0;i<M;i++) { 59 for(register int j=C[i][0]=1;j<=i;j++) { 60 C[i][j]=C[i-1][j-1]+C[i-1][j]; 61 } 62 } 63 for(register int i=0;i<=B;i++) { 64 for(register int j=pow[i][0]=1;j<M;j++) { 65 pow[i][j]=pow[i][j-1]*i; 66 } 67 } 68 } 69 int main() { 70 init(); 71 for(register int T=getint();T;T--) { 72 const int64 l=getint(),r=getint(); 73 for(register int i=0;i<B;i++) t[i]=getint(); 74 printf("%lld\n",solve(r)-solve(l-1)); 75 } 76 return 0; 77 }