【CF1267K】Key Storage——数论 排列组合 c++
由此我们可以求出n对应的序列。而这个序列的每一种排列都对应一个数。那么答案就是这个序列排列组合的数量。
当然,有两个条件需要满足:
1.由于是余数,所以第i位上的数小于i+1。
2.最后一位不能为0,因为那样在倒数第二位时n就已经为0,就会提前结束。
对于第一个条件,我们会发现对于任意x>y,那么x能选的位置y一定能选,但y能选的位置x不一定能选。因此我们从大往小挨个计算可行的情况即可。
对于第二个条件,我们只需按照最后一位可以为0的情况计算结果,再计算最后一位一定是0的结果(把0放到最后一位上),两数相减便是答案。
数组开到20就可以了。
是否预处理C无所谓,反正范围挺水的
#include<bits/stdc++.h> #define int long long using namespace std; int b[100]; int bl; int c[100][100];//j选i个 void init()//预处理C { for(int j=0;j<=20;j++) c[0][j]=1; for(int i=1;i<=20;i++) { for(int j=i;j<=20;j++) { c[i][j]=c[i-1][j-1]+c[i][j-1]; } } } void fen(int x)//x对应的序列 { int k=2; while(x) { b[x%k]++; x/=k; k++; bl++;//bl是序列的总元素数量 } return; } int pin() { int ans=1; int s=0; for(int i=20;i>=0;i--) { if(!b[i]) continue; ans*=c[b[i]][min(bl-i+1,bl)-s];//排列组合 s+=b[i]; } return ans; } signed main() { init(); int T; cin>>T; while(T--) { int n; cin>>n; memset(b,0,sizeof(b)); bl=0; fen(n); int x=pin(); int y=0; if(b[0]) { b[0]--; bl--; y=pin();//最后一位一定是零的情况 } cout<<x-y-1<<endl; } return 0; }