[AH2017/HNOI2017]抛硬币

280 篇文章 1 订阅

题目

传送门 to luogu

思路

化简式子题……因为一眼看出

a n s = ∑ j = 0 b ∑ i = j + 1 a ( a i ) ( b j ) ans=\sum_{j=0}^{b}\sum_{i=j+1}^{a}{a\choose i}{b\choose j} ans=j=0bi=j+1a(ia)(jb)

因为 ( a i ) = ( a a − i ) {a\choose i}={a\choose a-i} (ia)=(aia) ( b j ) = ( b b − j ) {b\choose j}={b\choose b-j} (jb)=(bjb) ,所以上式的两倍等于

∑ j = 0 b ∑ i = j + 1 a ( a i ) ( b j ) + ∑ j = 0 b ∑ i = j + 1 a ( a a − i ) ( b b − j ) \sum_{j=0}^{b}\sum_{i=j+1}^{a}{a\choose i}{b\choose j}+\sum_{j=0}^{b}\sum_{i=j+1}^{a}{a\choose a-i}{b\choose b-j} j=0bi=j+1a(ia)(jb)+j=0bi=j+1a(aia)(bjb)

不妨把第二个求和符号分成两个,一个部分计算 a − i ≤ b − j a-i\le b-j aibj 的情形,另一个则计算 a − i > b − j a-i>b-j ai>bj 的情形。那么答案的两倍为

∑ j = 0 b ∑ i = j + 1 a ( a i ) ( b j ) + ∑ j = 0 b ∑ i = j + 1 a − b + j − 1 ( a a − i ) ( b b − j ) + ∑ j = 0 b ∑ i = a − b + j a ( a a − i ) ( b b − j ) \sum_{j=0}^{b}\sum_{i=j+1}^{a}{a\choose i}{b\choose j}+\sum_{j=0}^{b}\sum_{i=j+1}^{a-b+j-1}{a\choose a-i}{b\choose b-j}+\sum_{j=0}^{b}\sum_{i=a-b+j}^{a}{a\choose a-i}{b\choose b-j} j=0bi=j+1a(ia)(jb)+j=0bi=j+1ab+j1(aia)(bjb)+j=0bi=ab+ja(aia)(bjb)

将最右边一项单独拿出来看看。显然 a − i ∈ [ 0 , b − j ] a-i\in[0,b-j] ai[0,bj] ,所以如果对 b − j b-j bj 换元,这一项就是 ∑ j = 0 b ∑ i = 0 j ( a i ) ( b j ) \sum_{j=0}^{b}\sum_{i=0}^{j}{a\choose i}{b\choose j} j=0bi=0j(ia)(jb) 。和第一项非常相似!这两项合在一起得到

∑ j = 0 b ( b j ) ∑ i = 0 a ( a i ) = 2 a + b \sum_{j=0}^{b}{b\choose j}\sum_{i=0}^{a}{a\choose i}=2^{a+b} j=0b(jb)i=0a(ia)=2a+b

于是

a n s = 2 a + b − 1 + 1 2 ∑ j = 0 b ∑ i = j + 1 a − b + j − 1 ( a a − i ) ( b b − j ) ans=2^{a+b-1}+\frac{1}{2}\sum_{j=0}^{b}\sum_{i=j+1}^{a-b+j-1}{a\choose a-i}{b\choose b-j} ans=2a+b1+21j=0bi=j+1ab+j1(aia)(bjb)

头疼的肯定是后面这一坨。单独考虑它。目前长得有点难看。 ( a a − i ) = ( a i ) {a\choose a-i}={a\choose i} (aia)=(ia) 毫无疑问。然后换个枚举方式,枚举 i − j i-j ij 的值,得到后面那一坨等于

1 2 ∑ j = 0 b ∑ i = 1 a − b − 1 ( a i + j ) ( b b − j ) \frac{1}{2}\sum_{j=0}^{b}\sum_{i=1}^{a-b-1}{a\choose i+j}{b\choose b-j} 21j=0bi=1ab1(i+ja)(bjb)

注意到 ( i + j ) + ( b − j ) = i + b (i+j)+(b-j)=i+b (i+j)+(bj)=i+b ,所以我们可以大胆使用 ( n + m x ) = ∑ i = 0 + ∞ ( n i ) ( m x − i ) {n+m\choose x}=\sum_{i=0}^{+\infty}{n\choose i}{m\choose x-i} (xn+m)=i=0+(in)(xim) 这一结论。结果写下这句话的我第二天就不知道为什么这是对的了。

其实就是先枚举 i i i ,于是 i + b i+b i+b 为定值了,而此时 b − j b-j bj 取遍 [ 0 , b ] [0,b] [0,b] ,于是内层求和就是 ( a + b b + i ) {a+b\choose b+i} (b+ia+b) 惹。于是这一坨就是

1 2 ∑ i = 1 a − b − 1 ( a + b i + b ) = 1 2 ∑ i = b + 1 a − 1 ( a + b i ) \frac{1}{2}\sum_{i=1}^{a-b-1}{a+b\choose i+b}=\frac{1}{2}\sum_{i=b+1}^{a-1}{a+b\choose i} 21i=1ab1(i+ba+b)=21i=b+1a1(ia+b)

我们要对 1 0 k 10^k 10k 取模,发现 2 2 2 是没有逆元的。怎么直接除掉 2 2 2 呢?

分两种情况。当 a + b a+b a+b 为奇数时,注意到很特殊的一点, [ b + 1 , a − 1 ] [b+1,a-1] [b+1,a1] 的中点刚好是 a + b 2 \frac{a+b}{2} 2a+b ,所以这是对称的,只求一半就做到了。 a + b a+b a+b 为偶数时,中间恰好剩下一个数。不过你在杨辉三角里一眼就能看出来,它就是上一层的中间那个数。所以也可以做到。

组合数要用扩展 L u c a s \tt Lucas Lucas 来求。要魔改一下。复杂度最终是 O ( T n log ⁡ a + 5 k k ) \mathcal O(Tn\log a+5^kk) O(Tnloga+5kk) 的,其中 n = a − b ≤ 1 0 5 n=a-b\le 10^5 n=ab105

代码

调了很久,终于发现:不能使用递推写法求逆元。因为 x x x 不是 p p p 的倍数时, p k   m o d   x p^k\bmod x pkmodx 也可能是 p p p 的倍数——比如商是 p p p 的倍数。

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long int_;
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline int qkpow(int_ b,int_ q,int Mod){
	int ans = 1;
	for(; q; q>>=1,b=b*b%Mod)
		if(q&1) ans = ans*b%Mod;
	return ans;
}

template < int p, int pk >
struct LUCAS{
	int jc[pk+1]; // factorial
	int invjc[pk+1]; // inv of jc
	LUCAS(){
		int phi = pk/p*(p-1);
		jc[0] = invjc[0] = 1;
		jc[1] = invjc[1] = 1;
		for(int i=2; i<=pk; ++i){
			jc[i] = jc[i-1]; // copy
			invjc[i] = invjc[i-1];
			if(i%p == 0) continue;
			jc[i] = 1ll*jc[i]*i%pk;
			invjc[i] = 1ll*invjc[i]
				*qkpow(i,phi-1,pk)%pk;
		}
	}
	int Lucas(int_ n,int_ m){
		if(n < m || m < 0) return 0;
		int z = 0; int_ ans = 1;
		for(int_ i=n; i; i/=p){
			ans = ans*jc[i%pk]%pk;
			z += i/pk; // how many [1,pk]
		}
		for(int_ i=m; i; i/=p){
			ans = ans*invjc[i%pk]%pk;
			z -= i/pk; // cashier
		}
		for(int_ i=n-m; i; i/=p){
			ans = ans*invjc[i%pk]%pk;
			z -= i/pk; // counter
		}
		if(z > 0) // something good
			ans = ans*qkpow(jc[pk],z,pk)%pk;
		else if(z < 0) // can't be worse
			ans = ans*qkpow(invjc[pk],-z,pk)%pk;
		z = 0; // 现在求 C(n,m) 中 p 的指数
		for(int_ i=p; i<=n; i*=p)
			z += (n/i)-(m/i)-((n-m)/i);
		ans = ans*qkpow(p,z,pk)%pk;
		return ans;
	}
};

const int MaxN = 1953125; // 5^10
const int inv = 1537323; // 1/512 mod MaxN
LUCAS< 5,MaxN > five;

const int inv512 = 109; // 1/MaxN mod 512
LUCAS< 2,512 > two;

const int Mod = 1000000000; // 1e9
int C(int_ n,int_ m){
	int_ first = two.Lucas(n,m);
// printf("f = %lld\n",first);
	int_ second = five.Lucas(n,m);
// printf("s = %lld\n",second);
	int ans = first*inv512*MaxN%Mod;
	ans += second*inv*512%Mod;
	return ans%Mod;
}

int op[20]; // output
int main(){
	int_ a, b; int k;
	while(~scanf("%lld",&a)){
		scanf("%lld %d",&b,&k);
		int ans = qkpow(2,a+b-1,Mod);
		for(int_ i=b+1; i<a+b-i; ++i)
			ans = (ans+C(a+b,i))%Mod;
		if(a == b) // special case
			ans = (ans+Mod-C(a+b-1,b-1))%Mod;
		else if(!((a+b)&1)) // even number
			ans = (ans+C(a+b-1,(a+b)/2))%Mod;
		for(int i=1; i<=9; ++i,ans/=10)
			op[i] = ans%10; // get digit
		for(int i=k; i>=1; --i)
			putchar(op[i]+'0');
		putchar('\n');
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来解决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需求。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值