題意:每個名字有名和姓兩部分,兩部分長度都是n,給定m種字元,且名和姓中不能有同一種字元,問有幾種可能性?
思路:
如果n個長度用x個字元表達,那就相當于n個不同小球放在x個不同的盒子裡。設其結果為f(x),那麼f(x) = x ^ n - C(x, 1) * f(x - 1) - C(x, 2) * f(x - 2) …… - C(x, x - 1) * f(1).
然後就枚舉兩邊各用了多少種字元統計結果。
反思:
1、正難則反的思想;
2、不應太早就放棄,必須堅持;
3、大數相減記得先加MOD再%,每一次有可能超MOD的乘法就%一下。
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
const int MOD = + ;
const int MAXN = + ;
ll c[MAXN][MAXN];
ll f[MAXN];
ll mod_pow(ll x, ll n)
{
ll res = ;
x = x % MOD;
while(n > )
{
if(n & ) res = res *x % MOD;
x = x * x % MOD;
n >>= ;
}
return res;
}
void Comb()
{
for(int i = ; i < MAXN; i++)
{
c[i][] = c[i][i] = ;
for(int j = ; j < i; j++)
{
c[i][j] = (c[i - ][j] + c[i - ][j - ]) % MOD;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie();
Comb();
int t; cin >> t;
while(t--)
{
int n, m; cin >> n >> m;
for(int i = ; i <= n && i < m; i++)
{
f[i] = mod_pow((ll)i, (ll)n);
for(int j = i - ; j >= ; j--)
{
f[i] = (f[i] - c[i][j] * f[j] % MOD + MOD) % MOD;
}
}
ll ans = ;
for(int i = ; i <= n && i < m; i++)
{
for(int j = ; j <= n && j <= m - i; j++)
{
ans += c[m][i] * f[i] % MOD * c[m - i][j] % MOD * f[j] % MOD;
ans %= MOD;
}
}
cout << ans << endl;
}
}