Problem

loj2023

题意概述:甲抛掷 \(a\) 次硬币,乙抛掷 \(b\) 次硬币,问有多少种情况甲正面向上的次数比乙多,答案对 \(10^k\) 取模

对于 \(10\%\) 的数据,\(a,b\le 20\);

对于 \(30\%\) 的数据,\(a,b\le 100\);

对于 \(70\%\) 的数据,\(a,b\le 100000\),其中有 \(20\%\) 的数据满足 \(a=b\);

对于 \(100\%\) 的数据,\(1\le a,b\le {10}^{15}, b\le a\le b+10000, 1\le k\le 9\),数据组数小于等于 \(10\)

10分

枚举俩人的抛掷方式,存下来合并后统计(没有存在的意义) \(O(2^a+2^b+ab)\)

30分

\(\sum_{i=1}^a\binom ai\sum_{j=0}^{\min(b,i-1)}\binom bj\),组合数需预处理 \(O(ab)\)

+20分

由于整个游戏是绝对公平的,即甲赢的概率与乙相当,考虑所有情况减去平局再除以\(2\),得到 \(\frac {2^{a+b}-\sum_{i=0}^a\binom ai^2}2=\frac {2^{a+b}-\binom {2a}a}2\)

70分

考虑预处理 \(f(i)=\sum_{j=0}^{\min(b,i-1)}\binom bj\),再枚举 \(i\) 求和 \(O(a+b)\)

(+20分与70分部分由于模数非质数则需crt或将阶乘拆解成\(k\cdot 2^x\cdot 5^y\)的形式进行模拟除法)

100分

+20做法可扩展,只需再加上甲赢且对称局面乙赢不了的情况再整体除以\(2\)即可,关键在于求新加的这个东西

设甲抛掷 \(a\) 次,得 \(x\) 次正面;乙抛掷 \(b\) 次,得 \(y\) 次正面

则当前情况甲赢,且对称情况乙赢不了(对称情况可以是平局)可以列出式子

\[\begin{cases}
x>y\\
a-x\geq b-y
\end{cases}
\]

已知 \(a,b\),解出 \(0<x-y\leq a-b\),则这一部分的答案已经可以表示为

\[\sum_{y=0}^b\sum_{x=y+1}^{y+(a-b)}\binom ax\binom by
\]

由于 \(a,b\) 都很大,但 \(a-b\leq 10^4\),从此入手,将其提出来

\[\sum_{t=1}^{a-b}\sum_{y=0}^b\binom a{y+t}\binom by
\]

考虑之前+20的做法中\(\sum\binom ai^2=\sum\binom ai\binom a{a-i}=\binom {2a}a\),这里后面\(\sum \binom a{y+t}\binom by=\sum \binom a{y+t}\binom b{b-y}=\binom {a+b}{(y+t)+(b-y)}=\binom {a+b}{b+t}\)

则后面答案为 \(\sum_{t=1}^{a-b}\binom {a+b}{b+t}\)

则整体答案为

\[\frac {2^{a+b}-\binom {2a}a+\sum_{t=1}^{a-b}\binom{a+b}{b+t}}2
\]

由于需要模合数,需要使用\(\mathsf {exLucas}\)解决……

至于如何除以 \(2\),可以将模数翻倍,最后直接除以 \(2\)

然后就TLE爆零了 分数不如暴力70,除此之外,还需要注意一些卡常技巧(从\(60s+\)到\(3s\)的华丽蜕变)

模数优化

由于模数只能是\(10^k\),所以可以考虑只模\(10^9\),最后再模\(10^k\),可以保证模数唯一,从而预处理模数的质因子分解

模数的质因子只有 \(2\) 和 \(5\),可以储存下来,对应的 \(p^k\) 分别为 \(2^{10},5^9\)

(到这里能拿 \(30\) 分啦)

调用优化

(优化效果特明显)

将两个模数开两个namespace,每个namespace内部由于模数相等,不需要传递模数

(到这里能拿 \(70\) 分啦)

组合数

由于 \(\binom nm = \binom n{n-m}\)

而得到的式子 \(\sum_{t=1}^{a-b}\binom{a+b}{b+t}\) 中以 \(\frac {a+b}2\) 为中心轴,两侧组合数对称,只要算一半即可(中间值特判一下)

Fac优化

由于每次询问的组合数下标都是 \(a+b\),所以可以在每组数据中预处理出 \(Fac(a+b)\),就不用每次重新调用了

预处理

\(p^k\)以内除去\(p\)的阶乘 是可以预处理的,同样 \(p^k\) 也是可以预处理的

至于是否要预处理所有 除去 \(p\) 的阶乘,由于询问次数较少,预处理耗时不比直接询问快

(到这里能拿 \(100\) 分啦)

玄学优化

(优化效果最明显)

若在函数 C(ll n,ll m,ll pi,ll pk)中,算出的 \(k\) 若比 \(pk\) 的幂次大,则直接返回 0ll

HN的题真毒,考场上遇到这题还是不要写正解,写了也被卡常

Code

#include <bits/stdc++.h>
using namespace std;
typedef long long ll; const int p = 2e9;
const int pw2 = 1024;
const int pw5 = 1953125; int fac[2][pw5+2];
int Pw [2][pw5+2]; void exgcd(ll a,ll b,ll&x,ll&y){
if(!b){x = 1, y = 0; return ;}
exgcd(b,a%b,y,x); y -= a/b*x;
} inline ll inv(ll n,ll mod){
ll x,y; exgcd(n,mod,x,y);
return (x+mod)%mod;
} namespace Lucas2{
const int pi = 2;
const int pk = pw2;
ll k_n;int Fac_n; inline ll inv(ll n){ll x,y; exgcd(n,pk,x,y);return (x+pk)%pk;}
inline ll qpow(ll A,ll B){ll res(1ll);while(B){if(B&1)res=res*A%pk;A=A*A%pk,B>>=1;}return res;} ll Fac(ll n){
if(!n) return 1ll;
ll res = 1ll;
res = fac[0][pk];
res = qpow(res,n/pk);
res = res * fac[0][n%pk]%pk;
return res * Fac(n/pi)%pk;
} inline ll C(ll n,ll m){
ll k = k_n;
for(ll i = m; i; i/=pi) k -= i/pi;
for(ll i=n-m; i; i/=pi) k -= i/pi;
if(k>=10) return 0ll;
ll d0 = Fac_n;
ll d1 = Fac(m);
ll d2 = Fac(n-m);
return d0 * inv(d1)%p * inv(d2)%p * Pw[0][k]%pk;
} inline ll CRT(ll b){return b * inv(p/pk)%p * (p/pk)%p;} inline void pre(ll n){
Fac_n = Fac(n),k_n = 0ll;
for(ll i = n; i; i/=pi)k_n += i/pi;
}
} namespace Lucas5{
const int pi = 5;
const int pk = pw5;
ll k_n;int Fac_n; inline ll inv(ll n){ll x,y; exgcd(n,pk,x,y);return (x+pk)%pk;}
inline ll qpow(ll A,ll B){ll res(1ll);while(B){if(B&1)res=res*A%pk;A=A*A%pk,B>>=1;}return res;} ll Fac(ll n){
if(!n) return 1ll;
ll res = 1ll;
res = fac[1][pk];
res = qpow(res,n/pk);
res = res * fac[1][n%pk]%pk;
return res * Fac(n/pi)%pk;
} inline ll C(ll n,ll m){
ll k = k_n;
for(ll i = m; i; i/=pi) k -= i/pi;
for(ll i=n-m; i; i/=pi) k -= i/pi;
if(k>=9) return 0ll;
ll d0 = Fac_n;
ll d1 = Fac(m);
ll d2 = Fac(n-m);
return d0 * inv(d1)%p * inv(d2)%p * Pw[1][k]%pk;
} inline ll CRT(ll b){return b * inv(p/pk)%p * (p/pk)%p;} inline void pre(ll n){
Fac_n = Fac(n),k_n = 0ll;
for(ll i = n; i; i/=pi)k_n += i/pi;
}
} ll exLucas(ll n,ll m){
ll res = 0ll;
res += Lucas2::CRT(Lucas2::C(n,m));
res += Lucas5::CRT(Lucas5::C(n,m));
return res%p;
} char ss[10];
void print(int x,int pp){
x%=(int)pow(10,pp);
ss[0] = '%', ss[1] = '0';
sprintf(ss+2,"%dd\n",pp);
printf(ss,x);
} void prework(int a,int b){
int*arr=fac[a==5];
int*trr= Pw[a==5];
arr[0]=trr[0]=1;
for(int i=1;i<=b;++i){
trr[i] = (ll)trr[i-1]*a%b;
arr[i] = arr[i-1];
if(i%a)arr[i]=(ll)arr[i]*i%b;
}
} inline ll qpow(ll A,ll B){
ll res(1ll);while(B){
if(B&1) res = res*A%p;
A = A*A%p, B>>=1;
}return res;
} int main(){
ll a,b;int pp;
prework(2,pw2);
prework(5,pw5);
while(~scanf("%lld%lld%d",&a,&b,&pp)){
ll res = qpow(2,a+b);
Lucas2::pre(a+b);
Lucas5::pre(a+b);
// res = (res - exLucas(a+b,a)+p)%p;
// for(int i=1;i<=a-b;++i) res = (res + exLucas(a+b,b+i))%p;
if(a == b){
res = (res - exLucas(a+b,a)+p)%p;
print(res>>1,pp); continue;
}
for(ll i=(a+b-1>>1);i!=b;--i)
res = (res + 2ll*exLucas(a+b,i))%p;
if(0 == ((a+b)&1))
res = (res + exLucas(a+b,a+b>>1))%p;
print(res>>1,pp);
}
return 0;
}

题解-HNOI2017 抛硬币的更多相关文章

  1. 【BZOJ4830】[HNOI2017]抛硬币(组合计数,拓展卢卡斯定理)

    [BZOJ4830][HNOI2017]抛硬币(组合计数,拓展卢卡斯定理) 题面 BZOJ 洛谷 题解 暴力是啥? 枚举\(A\)的次数和\(B\)的次数,然后直接组合数算就好了:\(\display ...

  2. bzoj 4830: [Hnoi2017]抛硬币 [范德蒙德卷积 扩展lucas]

    4830: [Hnoi2017]抛硬币 题意:A投a次硬币,B投b次硬币,a比b正面朝上次数多的方案数,模\(10^k\). \(b \le a \le b+10000 \le 10^{15}, k ...

  3. bzoj4830 hnoi2017 抛硬币

    题目描述 小 A 和小 B 是一对好朋友,他们经常一起愉快的玩耍.最近小 B 沉迷于**师手游,天天刷本,根本无心搞学习.但是已经入坑了几个月,却一次都没有抽到 SSR,让他非常怀疑人生.勤勉的小 A ...

  4. luogu P3726 [AH2017/HNOI2017]抛硬币

    传送门 我是真的弱,看题解都写了半天,,, 这题答案应该是\(\sum_{i=1}^{a}\binom{a}{i}\sum_{j=0}^{min(b,i-1)}\binom{b}{j}\) 上面那个式 ...

  5. [luogu3726 HNOI2017] 抛硬币 (拓展lucas)

    传送门 数学真的太优秀了Orz 数据真的太优秀了Orz 题目描述 小 A 和小 B 是一对好朋友,他们经常一起愉快的玩耍.最近小 B 沉迷于**师手游,天天刷本,根本无心搞学习.但是已经入坑了几个月, ...

  6. bzoj 4830: [Hnoi2017]抛硬币

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

  7. [AH/HNOI2017]抛硬币

    题目描述 小 A 和小 B 是一对好朋友,他们经常一起愉快的玩耍.最近小 B 沉迷于**师手游,天天刷本,根本无心搞学习.但是已经入坑了几个月,却一次都没有抽到 SSR,让他非常怀疑人生.勤勉的小 A ...

  8. 【刷题】BZOJ 4830 [Hnoi2017]抛硬币

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

  9. [HNOI2017]抛硬币

    Description 小A和小B是一对好朋友,他们经常一起愉快的玩耍.最近小B沉迷于××师手游,天天刷本,根本无心搞学习.但是已经入坑了几个月,却一次都没有抽到SSR,让他非常怀疑人生.勤勉的小A为 ...

随机推荐

  1. uiautomator2 使用Python测试 Android应用

    GitHub地址:https://github.com/openatx/uiautomator2 介绍 uiautomator2 是一个可以使用Python对Android设备进行UI自动化的库.其底 ...

  2. 在Web界面中实现Excel数据大量导入的处理方式

    在早期Bootstrap框架介绍中,我的随笔<结合bootstrap fileinput插件和Bootstrap-table表格插件,实现文件上传.预览.提交的导入Excel数据操作流程> ...

  3. Entity Framework Core系列之DbContext

    前言: EF Core DbContext表示与数据库的会话,并提供与数据库通信的API,具有以下功能: 数据库连接 数据操作,如查询和持久化 更改追踪 模型构建 数据映射 对象缓存 事务管理 数据库 ...

  4. 个人hp笔记本默认设置更改

    1.将F1-F12默认的多媒体键(调静音亮度控制声音大小等)改为功能键: (****笔记本型号为惠普****) ·进入BIOS方法:关机状态下,按电源键开机,立刻连续多次点击ESC,看到 F1.F2. ...

  5. JS实现刷新页面后回到记录时滚动条的位置

    window.onbeforeunload = function () { var scrollPos; if (typeof window.pageYOffset != 'undefined') { ...

  6. BBS 502 BadGateway 原因分析

    说明: LNMP架构. crontab里有每隔20分钟重启php的任务:然后我用python写了个每1分钟检测php-cgi进程是否存在的脚本,如果不存在则调用重启php的脚本,并邮件通知管理员.cr ...

  7. Magento2 可配置产品解决SKU流程

    选择可配置产品: 填写必填信息与库存 创建配置 执行四步后完成创建:4.1:选择需要的规格属性: 4.2:选择组合需要的属性值:4.3:根据您的选择,将创建3个新产品.使用此步骤自定义新产品的图像和价 ...

  8. Magento 2 Plugin - Interceptor - Magento 2插件 - 拦截器-插件开发

    Magento 2 Plugin - Interceptor - Magento 2插件 - 拦截器 Magento 2 Plugin is a technical plugin for your b ...

  9. mongodb 3.6 集群搭建:分片+副本集

    mongodb是最常用的nosql数据库,在数据库排名中已经上升到了前六.这篇文章介绍如何搭建高可用的mongodb(分片+副本)集群. 在搭建集群之前,需要首先了解几个概念:路由,分片.副本集.配置 ...

  10. vue 中 echart 在子组件中只显示一次的问题

    问题描述 一次项目开发过程中,需要做一些图表,用的是百度开源的 echarts. vue推荐组件化开发,所以就把每个图表封装成子组件,然后在需要用到该图表的父组件中直接使用. 实际开发中,数据肯定都是 ...