Killer Names (HDU6143 17多校赛)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=6143
题意:大概意思是输入n, m表示一共有m种字符,用这m种字符组成两段长度为n的字符串,字符种类可以不用完,但是对于这两段长为n的字符串其中包含的字符应不同,不同顺序算不同种(例如第一个字符串为aabb, 第二个串就不应该有a,b)。
解题思路:

先只考虑第一个字符串, 假设长度为n的字符串种包含 i(i=1,2,3...m) 种颜色,则对于这 i 种颜色的组成有Cim种,设 data[i] 为恰好用 i 种字符组成长度为n的串的组成形式数量,先假设每一种不计算重复,则有 in 种,对于其中的重复,假设 i=3 则对于长度为1的串会有 C1i 种, 对于长度为2的串会重复 C2i 种,同理可推得 data[i]=ini1j=1Cjidata[j] ,然后对于第二个串来说,当左边选择了 i 种字符后,他可以选择1,2,3...mi种字符, 故右边为 mij=1data[j] ,即为 (mi)n 种, 于是最终答案为 ans=ni=1Cimdata[i](mi)n ,其中 data[i]=ini1j=1Cjidata[j]

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;

LL C[2100][2100];
LL data[2100];
const int MOD=1e9+7;
LL pow_s(int a, int n){
    LL ans=1;
    for(int b=0; b<n; b++){
        ans*=a;
        ans%=MOD;
    }
    return ans;
}
int main() {
    C[0][0]=1;
    for(int a=1; a<=2000; a++){
        C[a][a]=C[a][0]=1;
        for(int b=1; b<=2000; b++){
            C[a][b]=(C[a-1][b-1]+C[a-1][b])%MOD;
        }
    }
    int T, n, m;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d", &n, &m);
        LL ans=0;
        for(int a=1; a<=m-1; a++){
            data[a]=pow_s(a, n);
            data[a]%=MOD;
            for(int b=a-1; b>=1; b--){
                data[a]=((data[a]-C[a][b]*data[b]%MOD)+MOD)%MOD;
            }
        }
        for(int a=1; a<=m-1; a++){
            LL l=data[a]*C[m][a]%MOD;
            LL r=pow_s(m-a, n);
            ans+=l%MOD*r%MOD;
            ans%=MOD;
        }
        printf("%lld\n", ans%MOD);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值