题意
埋和莫曾经是好朋友。埋是文科学霸,而莫却只是一个 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--
然后这里是从低位到高位,最后要倒过来一下再输出。