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

 

posted @ 2018-04-18 19:46  skylee03  阅读(184)  评论(0编辑  收藏  举报