Educational Codeforces Round 50 (Rated for Div. 2) C. Classy Numbers

C. Classy Numbers

题目链接:https://codeforces.com/contest/1036/problem/C

题意:

给出n个询问,每个询问给出Li,Ri,问在这个闭区间中有多少个数满足,除开0之外,最多只有4个数字。

 

题解:

由于题目给出的数满足前缀性质,所以我们可以直接求[1,r]这个区间中有多少个数满足就好了。

具体做法就是从高位往低位来看,然后如果当前数组不为0,假设为p,那么当前数组对答案的贡献就比较好计算了,假设后面的数有x位,目前已经有k个数字了。

那么分两种情况:一种是当前这位为0的时候,那么贡献就是C(x,3-k);另外一种就是当前这位为1~p-1的时候,贡献就是(p-1)*C(x,3-k-1)。

当前为p的情况我们留在后面统计就行了,因为这种情况主要是取决后面的数的。

细节见代码吧:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll C[30][30];
int T;
ll a,b;
int num[30],pow9[30]={1,9,81,729};
ll calc(ll x,ll k){
    ll ans = 0;
    if(x<=0) return 1;
    for(int i=0;i<=k;i++) ans+=C[x][i]*pow9[i];
    return ans ;
}
ll solve(ll x){
    memset(num,0,sizeof(num));
    int n;
    for(n=1;x;n++){
        num[n]=x%10;
        x/=10;
    }
    n--;
    ll ans = 0;
    for(int i=n,cur=3;i>=1;i--){
        if(!num[i]) continue ;
        ans+=calc(i-1,cur);
        cur--;
        ans+=(num[i]-1)*calc(i-1,cur);
        if(cur==0) break ;
        //if(i==1) ans++;
    }
    return ans ;
}
int main(){
    ios::sync_with_stdio(false);cin.tie(0);
    C[1][0]=1;C[1][1]=1;
    for(int i=2;i<=20;i++){
        C[i][0]=1;
        for(int j=1;j<=i;j++){
            C[i][j]=C[i-1][j]+C[i-1][j-1];
        }
    }
    cin>>T;
    while(T--){
        cin>>a>>b;
        //cout<<solve(b)<<" "<<solve(a-1)<< '\n';
        cout<<solve(b)-solve(a-1)<< '\n';
    }
    return 0;
}

 

posted @ 2019-03-17 22:12  heyuhhh  阅读(118)  评论(0编辑  收藏  举报