HNOI2017 拋硬幣(組合數學+擴充套件盧卡斯)
題目大意
給定,考慮所有長度為的01串和長度為的01串,統計所有前者中的1嚴格比後者多的方案數。
答案模。
題解
神仙思路……
的情況很簡單,只需要考慮有多少組“平局”即可,剩下的勝敗可以一一對應。
平局顯然就是,因此答案為。
考慮,此時我們會發現,任意一種不勝的情況,把所有位異或1必然對應一種勝的情況。於是此時需要考慮的僅僅是有多少局勝的全部異或1也仍然勝利(神仙!)。
令表示中1的個數,表示中1的個數,則需要滿足:,化簡可得。
因此,勝轉勝的總方案數如下:
於是就可以在的複雜度內計算了。答案就是。
但是這道題很毒瘤,模數不是質數……我們只能用擴充套件盧卡斯……
更毒瘤的是這道題還卡常,我們算和的時候可以先算出第一個組合數,然後用逆元之類的東西推出後面的,終於AC了……
#include <bits/stdc++.h>
namespace IOStream {
const int MAXR = 10000000;
char _READ_[MAXR], _PRINT_[MAXR];
int _READ_POS_, _PRINT_POS_, _READ_LEN_;
inline char readc() {
#ifndef ONLINE_JUDGE
return getchar();
#endif
if (!_READ_POS_) _READ_LEN_ = fread(_READ_, 1, MAXR, stdin);
char c = _READ_[_READ_POS_++];
if (_READ_POS_ == MAXR) _READ_POS_ = 0;
if (_READ_POS_ > _READ_LEN_) return 0;
return c;
}
template<typename T> inline void read(T &x) {
x = 0; register int flag = 1, c;
while (((c = readc()) < '0' || c > '9') && c != '-');
if (c == '-') flag = -1; else x = c - '0';
while ((c = readc()) >= '0' && c <= '9') x = x * 10 - '0' + c;
x *= flag;
}
template<typename T1, typename ...T2> inline void read(T1 &a, T2&... x) {
read(a), read(x...);
}
inline int reads(char *s) {
register int len = 0, c;
while (isspace(c = readc()) || !c);
s[len++] = c;
while (!isspace(c = readc()) && c) s[len++] = c;
s[len] = 0;
return len;
}
inline void ioflush() { fwrite(_PRINT_, 1, _PRINT_POS_, stdout), _PRINT_POS_ = 0; fflush(stdout); }
inline void printc(char c) {
_PRINT_[_PRINT_POS_++] = c;
if (_PRINT_POS_ == MAXR) ioflush();
}
inline void prints(char *s) {
for (int i = 0; s[i]; i++) printc(s[i]);
}
template<typename T> inline void print(T x, char c = '\n') {
if (x < 0) printc('-'), x = -x;
if (x) {
static char sta[20];
register int tp = 0;
for (; x; x /= 10) sta[tp++] = x % 10 + '0';
while (tp > 0) printc(sta[--tp]);
} else printc('0');
printc(c);
}
template<typename T1, typename ...T2> inline void print(T1 x, T2... y) {
print(x, ' '), print(y...);
}
}
using namespace IOStream;
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int MAXN = 2000005, MAXM = 10005;
ll pf2[MAXM], pf5[MAXN], aa[MAXM], bb[MAXM];
void extgcd(ll a, ll b, ll &x, ll &y) {
if (b > 0) {
extgcd(b, a % b, y, x);
y -= a / b * x;
} else x = 1, y = 0;
}
ll modpow(ll a, ll b, int c) {
ll res = 1;
for (; b; b >>= 1) {
if (b & 1) res = res * a % c;
a = a * a % c;
}
return res;
}
int get_inv(int x, int p) {
ll v, y;
extgcd(x, p, v, y);
return v;
}
int calc_fact(ll *pf, ll n, int p, int q) {
ll res = 1, cnt = 0;
for (; n; n /= q) {
res = res * pf[n % p] % p;
if (n >= p) cnt += n / p;
}
return res * modpow(pf[p], cnt, p) % p;
}
ll calc_cnt(ll n, int p) {
ll res = 0;
for (n /= p; n; n /= p) res += n;
return res;
}
int calc_binom(ll *pf, ll n, ll m, int p, int pk) {
if (m > n) return 0;
int a = calc_fact(pf, n, pk, p), b = calc_fact(pf, m, pk, p), c = calc_fact(pf, n - m, pk, p);
ll t = calc_cnt(n, p) - calc_cnt(m, p) - calc_cnt(n - m, p);
return (ll)a * get_inv(b, pk) % pk * get_inv(c, pk) % pk * modpow(p, t, pk) % pk;
}
ll solve(ll *pf, ll a, ll b, int p, int pk) {
if (a == b + 1) return 0;
int ta = calc_fact(pf, a + b, pk, p), tb = calc_fact(pf, a - 1, pk, p), tc = calc_fact(pf, b + 1, pk, p);
ll cnt = calc_cnt(a + b, p) - calc_cnt(a - 1, p) - calc_cnt(b + 1, p);
ll t = (ll)ta * get_inv(tb, pk) % pk * get_inv(tc, pk) % pk, res = t * modpow(p, cnt, pk) % pk;
for (int i = 2; i < a - b; i++) {
ll x = a - i + 1, y = b + i;
for (; x % p == 0; x /= p) ++cnt;
for (; y % p == 0; y /= p) --cnt;
t = t * (x % pk) % pk * get_inv(y % pk, pk) % pk;
res += t * modpow(p, cnt, pk) % pk;
}
return (res % pk + pk) % pk;
}
int main() {
ll a, b; int k;
while (~scanf("%lld%lld%d", &a, &b, &k)) {
int p2 = modpow(2, k + 1, 1000000000), p5 = modpow(5, k, 1000000000), pp = p2 * p5;
for (int i = pf2[0] = 1; i <= p2; i++) {
pf2[i] = pf2[i - 1];
if (i % 2) pf2[i] = pf2[i] * i % p2;
}
for (int i = pf5[0] = 1; i <= p5; i++) {
pf5[i] = pf5[i - 1];
if (i % 5) pf5[i] = pf5[i] * i % p5;
}
int inv1 = get_inv(p5, p2), inv2 = get_inv(p2, p5);
char prt[10] = "%00lld\n"; prt[2] = '0' + k;
if (a == b) {
ll x = calc_binom(pf2, a + b, b, 2, p2);
ll y = calc_binom(pf5, a + b, b, 5, p5);
x = inv1 * x % p2 * p5;
y = inv2 * y % p5 * p2;
x = ((x + y) % pp + pp) % pp;
printf(prt, (modpow(2, a + b - 1, pp) - x / 2 + pp) % (pp / 2));
} else {
ll x = solve(pf2, a, b, 2, p2), y = solve(pf5, a, b, 5, p5);
x = inv1 * x % p2 * p5, y = inv2 * y % p5 * p2;
x = ((x + y) % pp + pp) % pp;
printf(prt, (modpow(2, a + b - 1, pp) + x / 2) % (pp / 2));
}
}
return 0;
}
相關文章
- 擴充盧卡斯定理 / exlucas
- 動態規劃-硬幣組合數目動態規劃
- 拋硬幣(機率dp)
- 使用udev擴充套件ASM磁碟組dev套件ASM
- 拋硬幣中的反射原理反射
- 擴充套件叢集blk數套件
- 數論分塊擴充套件套件
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- 【數學】組合數學 - 排列組合
- 再學Blazor——擴充套件方法Blazor套件
- es6-數值擴充套件套件
- ES6數字擴充套件套件
- WCF擴充套件:行為擴充套件Behavior Extension套件
- CONNECT BY 擴充套件用法,實現獲取bom級聯擴充套件數量套件
- 鴻蒙NEXT開發案例:拋硬幣鴻蒙
- sql中的擴充套件學習SQL套件
- 動態規劃-最少硬幣組合問題動態規劃
- C#學習筆記-方法引數、擴充套件方法C#筆記套件
- 【Kotlin】擴充套件屬性、擴充套件函式Kotlin套件函式
- Sanic 擴充套件套件
- ORACLE 擴充套件Oracle套件
- 擴充套件工具套件
- 擴充套件歐幾里得套件
- DOM擴充套件套件
- 擴充套件ACL套件
- Lua擴充套件套件
- 照片擴充套件套件
- 擴充套件篇套件
- disable or 擴充套件套件
- 擴充套件表套件
- Mybatis擴充套件MyBatis套件
- 組合數學
- JMeter 擴充套件開發:擴充套件 TCP 取樣器JMeter套件TCP
- INFORMIX表的預設初始擴充套件、下一個擴充套件資料塊以及一個表允許的最大擴充套件數。ORM套件
- 數論學習筆記 (4):擴充套件歐幾里得演算法筆記套件演算法
- 學習筆記----擴充套件歐幾里德筆記套件
- 歐盟最大的ETF公司擴充套件加密貨幣產品套件加密
- ?用Chrome擴充套件管理器, 管理你的擴充套件Chrome套件