/** 题目:hdu6143 Killer Names 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6143 题意:有m种字符(可以不用完),组成两个长度为n的字符串,要求这两个字符串含有的字符没有相同的。 求有多少种方式组成这两个字符串。 思路:容斥+排列组合 反思一开始以为这题是dp,然后想了很久没想出来,觉得挺不好处理的,,能力不足。 后来想到是容斥。 f[n][1]表示长度为n的字符串用1种字符填充的方法数。 f[n][2] = 2^n - C(2,1)*f[n][1]; 两种的所有填充方式-一种的填充方式。 f[n][3] = 3^n - C(3,1)*f[n][1] - C(3,2)*f[n][2];... ... f[n][m] = m^n - sigma[1<=i<m]C(m,i)*f[n][i]; 那么可以枚举左边这个n长度字符串的组合方式用去i种字符,那么剩下那个字符串用剩下的字符任意组合即可。 注意m大于n的情况。 */ #include<bits/stdc++.h> #define LL long long using namespace std; const int N = 2005; const int mod = 1e9 + 7; LL fac[N], inv[N]; LL f[N][N]; void init() { inv[0] = inv[1] = 1; for(int i = 2; i < N; i++)inv[i] = (mod-mod/i)*inv[mod%i]%mod; for(int i = 2; i < N; i++)inv[i] = inv[i-1]*inv[i]%mod; fac[0] = 1; for(int i = 1; i < N; i++) fac[i] = fac[i-1]*i%mod; } LL Pow(LL a,LL b) { LL p = 1; while(b){ if(b&1) p = p*a%mod; a = a*a%mod; b >>= 1; } return p; } LL C(int n,int m) { return fac[n]*inv[m]%mod*inv[n-m]%mod; } void solve(int n,int m) { for(int i = 1; i <= min(n,m); i++){ f[n][i] = Pow(i,n); for(int j = 1; j < i; j++){ f[n][i] = (f[n][i]-f[n][j]*C(i,j)%mod+mod)%mod; } } } int main() { int T; int n, m; init(); cin>>T; while(T--) { scanf("%d%d",&n,&m); solve(n,m); LL ans = 0; int mis; if(m>n) mis = n; else mis = m-1; for(int i = 1; i <= mis; i++){ ans = (ans+C(m,i)*f[n][i]%mod*Pow(m-i,n)%mod)%mod; } cout<<ans<<endl; } return 0; }