链接: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]=in−∑i−1j=1Cji⋅data[j] ,然后对于第二个串来说,当左边选择了 i 种字符后,他可以选择1,2,3...m−i 种字符, 故右边为 ∑m−ij=1data[j] ,即为 (m−i)n 种, 于是最终答案为 ans=∑ni=1Cim⋅data[i]⋅(m−i)n ,其中 data[i]=in−∑i−1j=1Cji⋅data[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);
}
}