题意

埋和莫曾经是好朋友。埋是文科学霸,而莫却只是一个 OI 蒟蒻。一天,埋碰到一道难题跑来问莫。题目是这样的:有五个数字,分别是 5、2、1、3、9.莫可以取任意数字,每个数字可以取无限次。如:取两个 5,则组合为:55;取 2 与 1,则组合为:21。现在要问你所有组合中第 C(n, m)%1e9+7 (n>=m) 个数有多大?

输入描述

第 1 行一个数 t,表示询问的次数
接下来 t 行,每行两个数 n, m;详情见题目描述。
数据范围:
对于20%的数据,保证t=1
对于10%的数据,保证n=m
对于所有数据,保证
1<=t<=1000
1<=m<=n<=100

输出描述

t行,每行一个数字,表示所有组合中第 C(n, m)%1e9+7 (n>=m) 个大的数?

解析

这个题目描述的有点不清晰,我也是看了隔壁大佬的博客才明白的,大佬博客就是给定n和m,然后要求第 $C_{n}^{m}$ 大的数。

什么意思呢,就是这个数列的顺序是

1 2 3 5 9
11 12 13 15 19
21 22 23 25 29
31 32 33 35 39
51 52 53 55 59
91 92 93 95 99
111
然后继续往后推,例如n,m都为一,那么我们就是输出这个序列的第一个数,

然后我们来观察这个需例如你会发现数据规律是: 个一位数,个两位数,个三位数, 个四位数。

这样就能看出来了,本题就是转化成五进制数,然后再把字符串转化回1,2,3,5,9和0,1,2,3,4对应的字符串。

然后就是要注意,这个地方五进制的起点是1,而不是0;

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1e9+7;
ll qkpow(ll a, ll b) {       //快速幂
    ll ans = 1;
    while (b) {
        if (b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}
ll getInv(ll a) { return qkpow(a, mod - 2); }  //求逆元
ll C(ll n, ll m) {                             //组合数 C(n,m)
    if (m < 0) return 0;
    if (n < m) return 0;
    if (m > n - m) m = n - m;
    ll up = 1, down = 1;
    for (ll i = 0; i < m; i++) {
        up = up * (n - i) % mod;
        down = down * (i + 1) % mod;
    }
    return up * getInv(down) % mod;
}
char mp[5]={'1','2','3','5','9'};

int main(void){
    ios::sync_with_stdio(false);
    ll t;
    cin>>t;
    while (t--){
        ll n, m;
        cin>>n>>m;
        ll a;
        a=C(n,m);
        string ans="";
        while(a>0){
            a--;      //这里后面解释一下
            ans+=mp[a%5];
            a/=5;
        }
        reverse(ans.begin(),ans.end());
        cout<<ans<<endl;
    }
    return 0;
}

关于a--

图片说明

然后这里是从低位到高位,最后要倒过来一下再输出。