[SPOJ INS14G Kill them All]数学、排列组合
分类:排列组合
1. 题目链接
2. 题意描述
n个恐怖分子,Digo和Sharry要把他们全杀了。
恐怖分子按固定的顺序站好。每个恐怖分子都可以被Digo或Sharry杀。
Digo想要确保每个时刻他杀的恐怖分子都比Sharry多,问有多少种这样的方案。
输入数据:
t, 测试样例数,
n,恐怖分子数,
1<=t<=100000,1<=n<=1000000。
方案数mod1e9+7.
3. 解题思路
解法一:
我首先的想法是打表,找规律。然后也可以找出一个规律。即,
但是需要注意的是 nlog(MOD) 的复杂度是会TLE的。我们需要 O(n)预处理出[1,n]的逆元 。
原理:
解法二:
放到笛卡尔坐标系中考虑,向上走表示我赢了,向下走表示我输了。相当于我从原点出发,我的轨迹不能在过程中碰到x轴。
第一步一定向上,转化为从原点出发,轨迹在过程中不能跑到x轴下面。
枚举向上步数m,总方案数为C(n,m)(n剪了1),现在我们要减去非法方案数。对于非法的轨迹,我们把它第一次碰到y=-1后的轨迹按y=-1翻转,终点是确定的(自己想一想为什么),并且翻转后的轨迹和原轨迹之间一一对应。
ok,终点在哪里呢? m - (n - m) + p = -2 -> p = -2 + n - 2m -> x - (n - x) = -2 + n - 2m -> x = n - m - 1
所以非法方案数为C(n,n-m-1)=C(n,m+1),向上步数为m的方案数为C(n,m)-C(n,m+1);
累加消掉中间项,答案为C(n,(n+1)/2)
可以O(n)预处理出阶乘的逆元。然后O(1)求出组合数。
4. 实现代码
/**
* 解法一
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-8;
const int MAXN = 1000000 + 7;
const int MOD = 1e9 + 7;
int T, n;
LL ans[MAXN], inv[MAXN];
/*
void gen() {
static LL dp[MAXN][MAXN];
dp[1][1] = 1;
for(int i = 2; i < MAXN; ++i) {
LL sum = 0;
dp[i][0] = 0;
for(int j = 1; j <= i; ++j) {
if((j << 1) <= i) dp[i][j] = 0;
else dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % MOD;
sum = (sum + dp[i][j]) % MOD;
}
if(i <= 100) printf("%d %lld\n", i, sum);
}
}*/
template <typename T>
inline bool scan_d (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template<typename T>
void print(T x) {
static char s[33], *s1; s1 = s;
if (!x) *s1++ = '0';
if (x < 0) putchar('-'), x = -x;
while(x) *s1++ = (x % 10 + '0'), x /= 10;
while(s1-- != s) putchar(*s1);
}
template<typename T>
void println(T x) {
print(x); putchar('\n');
}
void init() {
inv[1] = ans[1] = 1;
// 预处理逆元
for(int i = 2; i < MAXN; ++i) {
inv[i] = (MOD -(MOD / i)) * inv[MOD % i] % MOD;
}
for(int i = 2; i < MAXN; ++i) {
if(i & 1) {
ans[i] = (ans[i - 1] << 1);
while(ans[i] >= MOD) ans[i] -= MOD;
} else {
ans[i] = ans[i - 1] * (i - 1) % MOD * inv[i >> 1] % MOD;
}
}
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
init();
scan_d(T);
while(T --) {
scan_d(n);
println(ans[n]);
}
return 0;
}
/**
* 解法二
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
const int INF = 0x3f3f3f3f;
const LL INFL = 0x3f3f3f3f3f3f3f3fLL;
const LB eps = 1e-8;
const int MAXN = 1000000 + 7;
const int MOD = 1e9 + 7;
int T, n;
LL ans[MAXN], fac[MAXN], inv[MAXN];
/*
void gen() {
static LL dp[MAXN][MAXN];
dp[1][1] = 1;
for(int i = 2; i < MAXN; ++i) {
LL sum = 0;
dp[i][0] = 0;
for(int j = 1; j <= i; ++j) {
if((j << 1) <= i) dp[i][j] = 0;
else dp[i][j] = (dp[i - 1][j - 1] + dp[i - 1][j]) % MOD;
sum = (sum + dp[i][j]) % MOD;
}
if(i <= 100) printf("%d %lld\n", i, sum);
}
}*/
template <typename T>
inline bool scan_d (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template<typename T>
void print(T x) {
static char s[33], *s1; s1 = s;
if (!x) *s1++ = '0';
if (x < 0) putchar('-'), x = -x;
while(x) *s1++ = (x % 10 + '0'), x /= 10;
while(s1-- != s) putchar(*s1);
}
template<typename T>
void println(T x) { print(x); putchar('\n');}
LL qpow(LL a, LL b) {
LL ret = 1;
while(b > 0) {
if(b & 1) ret = ret * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return ret;
}
LL C(LL n, LL k) { return fac[n] * inv[k] % MOD * inv[n - k] % MOD; }
void init() {
fac[0] = 1;
for(int i = 1; i < MAXN; ++i) fac[i] = fac[i - 1] * i % MOD;
inv[MAXN - 1] = qpow(fac[MAXN - 1], MOD - 2);
for(int i = MAXN - 2; i >= 0; --i) inv[i] = inv[i + 1] * (i + 1) % MOD;
for(int i = 0; i < MAXN; ++i) ans[i] = C(i - 1, i >> 1);
}
int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
freopen("output.txt", "w+", stdout); gen();
#endif // ___LOCAL_WONZY___
init();
scan_d(T); //scanf("%d", &T);
while(T --) {
scan_d(n); //scanf("%d", &n);
println(ans[n]); //printf("%lld\n", ans[n]);
}
return 0;
}