bzoj3622: 已经没有什么好害怕的了
题面。
先设fij表示前i个中有j个一定满足条件,且这j个映射到的目标位置两两不同。剩下的i - j个没有选。
然后求到最后fni的时候,还有n - i个空位,对应n - i个没有选的元素。乘上(n - i)!就是至少为i的方案数。
这些方案中,恰i个的只会被计算一次,而每种多于i个的(不妨设有j个)都会被计算C(j, i)次。于是减去。
容斥。显然可以n2。感觉容斥有两种,一种就是直接暴力套公式,还有就是这样按顺来,用正确的倒推前面的。
不妨设fij表示前i个糖果中有j个糖果比药片大。这里说一下为什么最后需要那个组合数。
因为你是减去“a比b大的对数多于i”,然后考虑你一个对数为j的方案,从中选i对出来就是组合数。
这Cji种你都会计算,而且都会乘上阶乘,导出这唯一的一种方案,也就是你这种方案被多算了Cji次。
1 #include <cstdio> 2 #include <algorithm> 3 4 const int N = 2010, MO = 1e9 + 9; 5 6 int a[N], b[N], f[N][N], n, k, g[N], pw[N], C[N][N]; 7 8 int main() { 9 10 //freopen("in.in", "r", stdin); 11 //freopen("my.out", "w", stdout); 12 13 scanf("%d%d", &n, &k); 14 if((n + k) & 1) { 15 printf("%d\n", 0); 16 return 0; 17 } 18 k = (n + k) / 2; 19 for(int i = 1; i <= n; i++) { 20 scanf("%d", &a[i]); 21 } 22 for(int i = 1; i <= n; i++) { 23 scanf("%d", &b[i]); 24 } 25 26 std::sort(a + 1, a + n + 1); 27 std::sort(b + 1, b + n + 1); 28 f[0][0] = 1; 29 int p = 0; 30 for(int i = 1; i <= n; i++) { 31 f[i][0] = 1; 32 } 33 for(int i = 1; i <= n; i++) { 34 while(b[p + 1] < a[i] && p < n) p++; 35 // printf("i = %d p = %d \n", i, p); 36 for(int j = 1; j <= n; j++) { 37 f[i][j] = (f[i - 1][j] + 1ll * f[i - 1][j - 1] * std::max(0, p - j + 1) % MO) % MO; 38 // printf("%d %d = %d + %d * %d \n", i, j, f[i - 1][j], f[i - 1][j - 1], std::max(0, p - j + 1)); 39 } 40 } 41 pw[0] = 1; 42 for(int i = 0; i <= n; i++) { 43 C[i][0] = C[i][i] = 1; 44 for(int j = 1; j < i; j++) { 45 C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MO; 46 } 47 if(i) pw[i] = 1ll * pw[i - 1] * i % MO; 48 } 49 /*for(int i = 1; i <= n; i++) { 50 for(int j = 1; j <= n; j++) { 51 printf("%d %d = %d \n", i, j, f[i][j]); 52 } 53 puts(""); 54 }*/ 55 56 for(int i = n; i >= k; i--) { 57 g[i] = 1ll * f[n][i] * pw[n - i] % MO; 58 //printf("%d = %d \n", i, g[i]); 59 for(int j = i + 1; j <= n; j++) { 60 //(g[i] += MO - g[j]) %= MO; 61 g[i] -= 1ll * g[j] * C[j][i] % MO; 62 if(g[i] < 0) g[i] += MO; 63 //printf("g -= %d * %d = %lld \n", g[j], C[j][i], g[i]); 64 } 65 //printf("%d = %d \n", i, g[i]); 66 } 67 printf("%d\n", (g[k] % MO + MO) % MO); 68 return 0; 69 } 70 /* 71 4 2 72 5 15 35 45 73 10 20 30 40 74 75 4 76 */
之前说的那两种写法都是可以的...原理不知道。这是第二种写法。
1 #include <cstdio> 2 #include <algorithm> 3 4 const int N = 2010, MO = 1e9 + 9; 5 6 int a[N], b[N], f[N][N], n, k, g[N], pw[N], C[N][N]; 7 8 int main() { 9 10 //freopen("in.in", "r", stdin); 11 //freopen("my.out", "w", stdout); 12 13 scanf("%d%d", &n, &k); 14 if((n + k) & 1) { 15 printf("%d\n", 0); 16 return 0; 17 } 18 k = (n + k) / 2; 19 for(int i = 1; i <= n; i++) { 20 scanf("%d", &a[i]); 21 } 22 for(int i = 1; i <= n; i++) { 23 scanf("%d", &b[i]); 24 } 25 26 std::sort(a + 1, a + n + 1); 27 std::sort(b + 1, b + n + 1); 28 f[0][0] = 1; 29 int p = 0; 30 for(int i = 1; i <= n; i++) { 31 f[i][0] = 1; 32 } 33 for(int i = 1; i <= n; i++) { 34 while(b[p + 1] < a[i] && p < n) p++; 35 // printf("i = %d p = %d \n", i, p); 36 for(int j = 1; j <= n; j++) { 37 f[i][j] = (f[i - 1][j] + 1ll * f[i - 1][j - 1] * std::max(0, p - j + 1) % MO) % MO; 38 // printf("%d %d = %d + %d * %d \n", i, j, f[i - 1][j], f[i - 1][j - 1], std::max(0, p - j + 1)); 39 } 40 } 41 pw[0] = 1; 42 for(int i = 0; i <= n; i++) { 43 C[i][0] = C[i][i] = 1; 44 for(int j = 1; j < i; j++) { 45 C[i][j] = (C[i - 1][j] + C[i - 1][j - 1]) % MO; 46 } 47 if(i) pw[i] = 1ll * pw[i - 1] * i % MO; 48 } 49 /*for(int i = 1; i <= n; i++) { 50 for(int j = 1; j <= n; j++) { 51 printf("%d %d = %d \n", i, j, f[i][j]); 52 } 53 puts(""); 54 }*/ 55 56 /*for(int i = n; i >= k; i--) { 57 g[i] = 1ll * f[n][i] * pw[n - i] % MO; 58 //printf("%d = %d \n", i, g[i]); 59 for(int j = i + 1; j <= n; j++) { 60 //(g[i] += MO - g[j]) %= MO; 61 g[i] -= 1ll * g[j] * C[j][i] % MO; 62 if(g[i] < 0) g[i] += MO; 63 //printf("g -= %d * %d = %lld \n", g[j], C[j][i], g[i]); 64 } 65 //printf("%d = %d \n", i, g[i]); 66 }*/ 67 int ans = 0; 68 for(int i = k; i <= n; i++) { 69 int temp = 1ll * f[n][i] * pw[n - i] % MO * C[i][k] % MO; 70 if((i - k) & 1) ans = (ans - temp) % MO; 71 else ans = (ans + temp) % MO; 72 } 73 74 75 printf("%d\n", (ans % MO + MO) % MO); 76 return 0; 77 } 78 /* 79 4 2 80 5 15 35 45 81 10 20 30 40 82 83 4 84 */
灵感来自bzoj2839。