[HNOI2017]抛硬币(组合数学,扩展lucas)

6人阅读 评论(0) 收藏 举报
分类:

Description

小A和小B抛硬币,小A抛a次,小B抛b次,求小A赢过小B的方案数。

Solution

这道题ab较小,所以可以考虑关于ab的式子。

  • a=b,若a=b,则唯一需要考虑的平局的情况(因为情况是对称的)。
    s表示平局的方案数,则

    s=i=0aCaiCai=i=0aCaaiCai=C2aa

    ans=2a+bs2

  • a>b,则无论如何也有一种情况使得小A赢,则只需要加上两种对称情况小A都赢的次数s
    设小B赢了i次,小A赢了i+j次。

    a(i+j)>bijab1

    s=i=0bj=1j=ab1CbiCai+j=i=0bj=1j=ab1CbiCai+j=i=0bj=1j=ab1CbbiCai+j=j=1ab1Ca+bb+j

    然后用扩展lucas搞一搞就行了。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 10005, mod = (int)1e9;
typedef long long lint;

int pow(int x, lint k, int mod)
{
    int ret = 1;
    while (k) {
        if (k & 1) ret = (lint)ret * x % mod;
        x = (lint)x * x % mod; k >>= 1;
    }
    return ret;
}

const int p1 = 512, p2 = 1953125, inv1 = 109, inv2 = 1537323, inv3 = 976563;
int fac1[p1 + 5], fac2[p2 + 5];

void exgcd(lint a, lint b, lint &x, lint &y)
{
    if (b == 0) x = 1, y = 0;
    else exgcd(b, a % b, y, x), y -= x * (a / b);
}

int inv(int x, int p)
{
    lint a, b;
    exgcd(x, p, a, b);
    a = (a % p + p) % p;
    return a;
}

void prepare()
{
    fac1[0] = 1;
    for (int i = 1; i <= p1; ++i) fac1[i] = (lint)(i % 2 ? i : 1) * fac1[i - 1] % p1;
    fac2[0] = 1;
    for (int i = 1; i <= p2; ++i) fac2[i] = (lint)(i % 5 ? i : 1) * fac2[i - 1] % p2;
}

int fact1(lint n)
{
    if (n <= 0) return 1;
    return (lint)pow(fac1[p1], n / p1, p1) * fac1[n % p1] % p1 * fact1(n / 2) % p1;
}

int C1(lint n, lint m, bool type)
{
    int A = fact1(n), B = fact1(n - m), C = fact1(m), cnt = 0;
    for (lint x = n; x; x >>= 1) cnt += x / 2;
    for (lint x = n - m; x; x >>= 1) cnt -= x / 2;
    for (lint x = m; x; x >>= 1) cnt -= x / 2;
    if (type) return (lint)A * inv(B, p1) % p1 * inv(C, p1) % p1 * pow(2, cnt, p1) % p1;
    else return (lint)A * inv(B, p1) % p1 * inv(C, p1) % p1 * pow(2, cnt - 1, p1) % p1;
}

int fact2(lint n)
{
    if (n <= 0) return 1;
    return (lint)pow(fac2[p2], n / p2, p2) * fac2[n % p2] % p2 * fact2(n / 5) % p2;
}

int C2(lint n, lint m, bool type)
{
    int A = fact2(n), B = fact2(n - m), C = fact2(m), cnt = 0;
    for (lint x = n; x; x /= 5) cnt += x / 5;
    for (lint x = n - m; x; x /= 5) cnt -= x / 5;
    for (lint x = m; x; x /= 5) cnt -= x / 5;
    if (type) return (lint)A * inv(B, p2) % p2 * inv(C, p2) % p2 * pow(5, cnt, p2) % p2;
    else return (lint)A * inv(B, p2) % p2 * inv(C, p2) % p2 * pow(5, cnt, p2) % p2 * inv3 % p2;
}

int C(lint n, lint m, bool type)
{
    int A = C1(n, m, type), B = C2(n, m, type);
    A = (lint)(A * p2 % mod) * inv1 % mod;
    B = (lint)(B * p1 % mod) * inv2 % mod;
    return (A + B) % mod;
}

void print(int x, int k)
{
    int a[15] = {0}, cnt = 0;
    while (x) a[++cnt] = x % 10, x /= 10;
    for (int i = k; i >= 1; --i) putchar(a[i] + '0');
    puts("");
}

int main()
{
    freopen("coin.in", "r", stdin);
    freopen("coin.out", "w", stdout);

    prepare();

    lint a, b, k;
    while (scanf("%lld%lld%lld", &a, &b, &k) == 3) {
        if (a == b) print(((pow(2, a + b - 1, mod) - C(a + b, a, 0)) % mod + mod) % mod, k);
        else {
            lint ans = pow(2, a + b - 1, mod);
            if (((a + b) & 1) == 0) {
                ans += C(a + b, (a + b) / 2, 0);
                if (ans >= mod) ans -= mod;
            }
            for (lint i = (a + b) / 2 + 1; i <= a - 1; ++i) {
                ans += C(a + b, i, 1);
                if (ans >= mod) ans -= mod;
            }
            print(ans, k);
        }
    }

    return 0;
}
查看评论

[BZOJ4830][HNOI2017]抛硬币-扩展Lucas定理

抛硬币Description小A和小B是一对好朋友,他们经常一起愉快的玩耍。最近小B沉迷于**师手游,天天刷本,根本无心搞学习。但是已经入坑了几个月,却一次都没有抽到SSR,让他非常怀疑人生。勤勉的小...
  • zlttttt
  • zlttttt
  • 2017年05月18日 00:25
  • 529

HNOI2017 抛硬币

题解实际上就是要求∑a+bi=b+1Cia+b\sum_{i=b+1}^{a+b}C_{a+b}^i,组合数取模即可。
  • Akak__ii
  • Akak__ii
  • 2017年04月23日 09:06
  • 789

4830: [Hnoi2017]抛硬币

4830: [Hnoi2017]抛硬币Time Limit: 30 Sec Memory Limit: 128 MB Submit: 220 Solved: 73 [Submit][Statu...
  • CRZbulabula
  • CRZbulabula
  • 2017年05月03日 16:03
  • 723

[组合数取模] BZOJ 4830 [Hnoi2017]抛硬币

习惯性交换aa和bb 令b≥ab\geq a 首先特判a=ba=b 这时答案为22a−Ca2a2{2^{2a}-C_{2a}^a}\over 2 其实就是所有情况减去平局的情况 剩下的不是A...
  • u014609452
  • u014609452
  • 2017年04月20日 07:20
  • 1668

[BZOJ4828][Hnoi2017]大佬-DP+DFS

大佬Description人们总是难免会碰到大佬。他们趾高气昂地谈论凡人不能理解的算法和数据结构,走到任何一个地方,大佬的气场就能让周围的人吓得瑟瑟发抖,不敢言语。你作为一个OIER,面对这样的事情非...
  • zlttttt
  • zlttttt
  • 2017年05月17日 23:20
  • 267

(带讲解)bzoj 4830 抛硬币 组合式推导+拓展lucas

卡常!!!题意:有两个人,第一个人要扔a次硬币,第二个人扔b次硬币(a>b),如果第一个人的正面朝上比b多则a获胜,求a获胜的话有多少种方案。要求a-b的范围是1e5,但是a和b都很大,所以复杂度要和...
  • thchuan2001
  • thchuan2001
  • 2017年07月02日 21:01
  • 345

洛谷3723 [AH2017/HNOI2017]礼物

标签:FFT 题目 题目传送门 题目描述 我的室友最近喜欢上了一个可爱的小女生。马上就要到她的生日了,他决定买一对情侣手环,一个留给自己,一个送给她。每个手环上各有 n 个装饰物,并且每个装饰...
  • qwerty1125
  • qwerty1125
  • 2018年02月26日 15:05
  • 56

HNOI2017滚粗记

day0考前晚上写了一波NOI2005维修数列,Uoj228基础数据结构练习题,Uoj4魔法森林(97分)和Picks的毒瘤数据结构一题,然后开始起飞。day1利益相关:正式选手 我只想biao出题...
  • CuSO45H20
  • CuSO45H20
  • 2017年04月15日 19:18
  • 1735

bzoj4830/洛谷P3726 抛硬币 扩展Lucas

题目分析 首先考虑a=b的情况,那么对于一种B获胜的方案序列(比如二人都抛3次,A第三次正面朝上,B第一次和第二次正面朝上,序列就是001110),将每一位都异或1,就变成了A获胜的,当然,还要减去...
  • litble
  • litble
  • 2018年03月17日 22:11
  • 56
    个人资料
    持之以恒
    等级:
    访问量: 5740
    积分: 497
    排名: 10万+
    友链