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

京公网安备 11010502036488号