Codeforces EduRound 50 C. Classy Numbers (组合数学)

1036C

定义Classy Integer为不超过三个数位为非零数的数。给出q次询问,每次要求给出[l,r]区间中Classy Integer的数目。

计算[l,r]的结果,考虑以cal(r)-cal(l)的形式给出。考虑某个数字的前缀有k个非0的数位,后缀的长度为x,且前缀之后第一位为d的情况。如果d为0,这个时候显然答案为0,。否则,因为我们要计算的是[1,r]区间的答案,在小于r的情况下就可以在d这个位置填0~d-1的数。填0的时候,就在后面的x-1位中选若干位填非0数,否则也同理。

容易得出cal(n)的答案是\sum_{i=0}^{3-k}\binom{x-1}{i}9^{i}+(d-1)\sum_{i=0}^{3-k-1}\binom{x-1}{i}9^{i}

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <queue>
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn = 300050;
const ll INF = (1LL << 62) - 1;
const double eps = 1e-8;

int t, p9[5] = {1, 9, 81, 729};
char s[105];
ll L, R;

ll C(int a, int b)
{
    if(a < b || a < 0 || b < 0) return 0;
    if(b == 0 || a == b) return 1;
    ll tmp = 1;
    for(int i = a;i > a - b;i--) tmp *= i;
    for(int i = 1;i <= b;i++) tmp /= i;
    return tmp;
}

ll getnum(int n, int m)
{
    ll res = 0;
    for(int i = 0;i <= m;i++)
        res += C(n, i)*p9[i];
    return res;
}

ll cal(ll n)
{
    memset(s, 0, sizeof(s));
    int num = 0, cur = 3;
    ll tmp = n, res = 0;
    while(tmp) {s[num++] = '0' + tmp % 10; tmp /= 10;}
    for(int i = num - 1;i >= 0;i--)
    {
        if(s[i] == '0') continue;
        res += getnum(i, cur);
        cur--;
        if(cur < 0) break;
        res += getnum(i, cur)*(s[i] - '1');
    }
    return res;
}

int main()
{
    scanf("%d", &t);
    while(t--)
    {
        scanf("%I64d%I64d", &L, &R);
        ll ans = cal(R + 1) - cal(L);
        printf("%I64d\n", ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/NPU_SXY/article/details/82772631