Killer Names 2017 多校 8

本文详细解析了一个关于组合计数的问题,通过排列组合的方法求解使用特定数量的字符构成姓名的不同组合方式,避免了姓名中出现重复字符的情况,并提供了一个递归公式用于计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Killer Names     2017 多校八;点击打开链接



题意:  给你 m  种字符,求用 m 种字符组成   姓和名   (每个长度为  n )   ,有多少种组合方法?(姓和名中不能有相同的字符)


思路:排列组合;

比赛的时候"成功"的没有推出来,太菜。。。

先说一下比赛时候的思路吧: 其实到现在搜题解的时候发现就跟别人后面求排列的时候有一点不一样,当时想的是怎样求出  x 个字符  全部用上排  n  长度的字符串有多少种,然后就没有找到公式,后来换了一种算出所有的  种数,然后减去重复的部分,奈何样例都过不了。

后来看别人的代码,发现求  x  个字符排 n 长度的字符串可以先算出所有然后去重复,而重复的部分刚好与  x-1  个字符排 n  长度的字符串有关.  其实就是一个递推。  


整个思路说一下吧:  给"名"  分 x 个字符,然后排列有   C(m,x)*(m-x)^n*(x^n-C(x,x-1)* f [ x-1   ];

f[  ] 为一个递推公式;

具体看大佬的代码:  点击打开链接


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 2005;
const int mod = 1e9+7;
ll c[maxn][maxn],n,m,f[maxn];

ll pow_mod(ll a,ll b)//快速幂
{
    ll res = 1;
    while(b)
    {
        if(b&1) res = (res*a)%mod;
        a = (a*a)%mod;
        b>>=1;
    }
    return res;
}

void init()//组合数
{
    for(int i=0;i<maxn;i++)
    {
        for(int j=0;j<=i;j++)
        {
            if(j==0 || j==i) c[i][j]=1;
            else c[i][j] = (c[i-1][j-1]+c[i-1][j])%mod;
        }
    }
}

int main()
{
    int t;
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&m);
        ll ans=0;
        for(int i=1;i<=min(n,m);i++)
        {
            if(i==1)
            {
                f[1]=1;
                ll res = (c[m][1]*pow_mod(m-1,n))%mod;
                ans += res;
                ans %= mod;
            }
            else
            {
                ll res = (c[m][i]*pow_mod(m-i,n))%mod;
                ll tmp = 0;
                for(int j=1;j<i;j++)//递推求解f[i]
                {
                    tmp += (c[i][j]*f[j])%mod;
                    tmp %= mod;
                }
                f[i] = pow_mod(i,n)-tmp;
                res *= f[i];
                res %= mod;
                ans += res;
                ans %= mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值