令dp[i]表示在n个人中,有 i 个人获得第一名的方案数,转移方程为dp[i] = C(i, n) * dp[n - i]。C(i, n)就是从n个人中选 i 个第一,那么剩下的n - i 个人必须都不是第一,所以就从dp[n - i]转移过来。
因为模数不是质数,所以O(n2)杨辉三角递推。然后O(n2)dp预处理,O(1)查询。
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 #include<cstdlib> 7 #include<cctype> 8 #include<stack> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 #define enter puts("") 13 #define space putchar(' ') 14 #define Mem(a, x) memset(a, x, sizeof(a)) 15 #define rg register 16 typedef long long ll; 17 typedef double db; 18 const int INF = 0x3f3f3f3f; 19 const db eps = 1e-8; 20 const int maxn = 1e3 + 5; 21 const int mod = 10056; 22 inline ll read() 23 { 24 ll ans = 0; 25 char ch = getchar(), las = ' '; 26 while(!isdigit(ch)) las = ch, ch = getchar(); 27 while(isdigit(ch)) ans = ans * 10 + ch - '0', ch = getchar(); 28 if(las == '-') ans = -ans; 29 return ans; 30 } 31 inline void write(ll x) 32 { 33 if(x < 0) putchar('-'), x = -x; 34 if(x >= 10) write(x / 10); 35 putchar(x % 10 + '0'); 36 } 37 38 int c[maxn][maxn], dp[maxn]; 39 40 int main() 41 { 42 c[0][0] = 1; 43 for(int i = 1; i < maxn; ++i) 44 { 45 c[i][0] = 1; 46 for(int j = 1; j < maxn; ++j) 47 c[i][j] = (c[i - 1][j] + c[i - 1][j - 1]) % mod; 48 } 49 dp[0] = 1; 50 for(int i = 1; i < maxn; ++i) 51 for(int j = 1; j <= i; ++j) 52 dp[i] = (dp[i] + c[i][j] * dp[i - j] % mod) % mod; 53 int T = read(); 54 for(int i = 1; i <= T; ++i) 55 { 56 int n = read(); 57 printf("Case %d: %d ", i, dp[n]); 58 } 59 return 0; 60 }