题目链接:HDU 6333 Harvest of Apples
题目大意
T组询问( T≤105 T ≤ 10 5 ),每次询问求 S(n,m)=∑mi=0C(n,m)mod(109+7) S ( n , m ) = ∑ i = 0 m C ( n , m ) m o d ( 10 9 + 7 )
思路
可以得出:
S(n, m) = S(n, m - 1) + C(n, m);
S(n, m) = 2 * S(n - 1, m) - C(n - 1, m);
进而推出:
S(n + 1, m) = 2 * S(n, m) - C(n, m);
S(n - 1, m) = (S(n, m) + C(n - 1, m)) / 2;
S(n, m + 1) = S(n, m) + C(n, m + 1);
S(n, m - 1) = S(n, m) - C(n, m);
即已知(n, m)答案可以O(1)求出(n+1, m), (n-1, m), (n, m+1), (n, m-1)答案
莫队算法
代码
Accepted 6333 374MS 6088K 2028 B G++
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100, mod = 1e9 + 7;
ll inv[maxn], fac[maxn], finv[maxn];
void init()
{
inv[1] = 1;
for (int i = 2; i < maxn; ++i)
inv[i] = inv[mod % i] * (mod - mod / i) % mod; //O(n)预处理逆元
fac[0] = finv[0] = 1;
for (int i = 1; i < maxn; ++i)
{
fac[i] = fac[i - 1] * i % mod;
finv[i] = finv[i - 1] * inv[i] % mod;
}
}
inline ll comb(int n, int m)
{
if (m < 0 || m > n) return 0;
return fac[n] * finv[n - m] % mod * finv[m] % mod;
}
int block[maxn];
struct Query
{
int n, m, id;
Query(int a = 0, int b = 0, int c = 0)
: n(a), m(b), id(c) {}
bool operator<(const Query&o) const
{
if (block[n] == block[o.n])
{
if (block[n] % 2 == 1) return m < o.m;
else return m > o.m;
}
return n < o.n;
}
} querys[maxn];
ll now, ans[maxn];
// S(n, m) = S(n, m - 1) + C(n, m)
// S(n, m) = 2 * S(n - 1, m) - C(n - 1, m)
// S(n + 1, m) = 2 * S(n, m) - C(n, m);
// S(n - 1, m) = (S(n, m) + C(n - 1, m)) / 2;
// S(n, m + 1) = S(n, m) + C(n, m + 1);
// S(n, m - 1) = S(n, m) - C(n, m);
inline void addn(int n, int m)
{
now = ((2 * now - comb(n, m)) % mod + mod) % mod;
}
inline void subn(int n, int m)
{
now = (now + comb(n - 1, m)) * inv[2] % mod;
}
inline void addm(int n, int m)
{
now = (now + comb(n, m + 1)) % mod;
}
inline void subm(int n, int m)
{
now = (now - comb(n, m) + mod) % mod;
}
int main()
{
init();
int T;
scanf("%d", &T);
for (int i = 0; i < T; ++i)
{
scanf("%d%d", &querys[i].n, &querys[i].m);
querys[i].id = i;
}
int block_size = (int)sqrt(T);
for (int i = 0; i < T; ++i)
block[i] = i / block_size + 1;
sort(querys, querys + T);
now = 2;
int n = 1, m = 1;
for (int i = 0; i < T; ++i)
{
for (; n < querys[i].n; ++n) addn(n, m);
for (; n > querys[i].n; --n) subn(n, m);
for (; m < querys[i].m; ++m) addm(n, m);
for (; m > querys[i].m; --m) subm(n, m);
ans[querys[i].id] = now;
}
for (int i = 0; i < T; ++i) printf("%lld\n", ans[i]);
return 0;
}