首页 > 编程语言 > 详细

【CF1267K】Key Storage——数论 排列组合 c++

时间:2021-02-22 20:18:33      阅读:57      评论:0      收藏:0      [点我收藏+]

根据题意可以得知,每一个n?值对应唯一的序列,即同样的n?对应同样的序列,那么就可以转换成不同的序列对应不同的?n

由此我们可以求出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;
}

 

【CF1267K】Key Storage——数论 排列组合 c++

原文:https://www.cnblogs.com/CGY2007/p/14431900.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!