1. 程式人生 > >[bzoj4830][lucas定理][數論]拋硬幣

[bzoj4830][lucas定理][數論]拋硬幣

Description

小A和小B是一對好朋友,他們經常一起愉快的玩耍。最近小B沉迷於**師手遊,天天刷本,根本無心搞學習。但是
已經入坑了幾個月,卻一次都沒有抽到SSR,讓他非常懷疑人生。勤勉的小A為了勸說小B早日脫坑,認真學習,決
定以拋硬幣的形式讓小B明白他是一個徹徹底底的非洲人,從而對這個遊戲絕望。兩個人同時拋b次硬幣,如果小A
的正面朝上的次數大於小B正面朝上的次數,則小A獲勝。但事實上,小A也曾經沉迷過拉拉遊戲,而且他一次UR也
沒有抽到過,所以他對於自己的運氣也沒有太大把握。所以他決定在小B沒注意的時候作弊,悄悄地多拋幾次硬幣
,當然,為了不讓小B懷疑,他不會拋太多次。現在小A想問你,在多少種可能的情況下,他能夠勝過小B呢?由於
答案可能太大,所以你只需要輸出答案在十進位制表示下的最後k位即可。

Input

有多組資料,對於每組資料輸入三個數a,b,k,分別代表小A拋硬幣的次數,小B拋硬幣的次 數,以及最終答案保留多少位整數。
1≤a,b≤10^15,b≤a≤b+10000,1≤k≤9,資料組數小於等於10。

Output

對於每組資料,輸出一個數,表示最終答案的最後k位為多少,若不足k位以0補全。

Sample Input

2 1 9

3 2 1

Sample Output

000000004

6

HINT

【樣例解釋】

對於第一組資料,當小A拋2次硬幣,小B拋1次硬幣時,共有4種方案使得小A正面朝上的

次數比小B多。(01,0),(10,0),(11,0),(11,1)

對於第二組資料,當小A拋3次硬幣,小B拋2次硬幣時,共有16種方案使得小A正面朝上的次數比小B多。(001,00),

(010,00),(100,00),(011,00),(101,00),(110,00),(111,00),(011,01),(101,01),(110,01),(111,01),(011,10),

(101,10),(110,10),(111,10),(111,11)

題解

思路還是非常神仙的…
不妨把拋硬幣的操作看成01序列
先從A=B開始考慮
01接起來,顯然是個2*A的序列
這時候每個A贏的方案都對應了一個01反轉之後B贏的方案
我們需要去掉的就只有A和B平手的方案
就是

C A i C B i \sum C_{A}^{i}*C_{B}^{i} ,換一下就是 C A i C B B i \sum C_{A}^{i}C_{B}^{B-i}
就是2*A的前A個選i個,後A個選A-i個,那麼就是
2 A + B C 2 A A 2 \frac{2^{A+B}-C_{2A}^{A}}{2}
拓展到 A B A\neq B
在某些A贏的情況下01反轉後仍然還可以做到是B贏
然而B贏的情況01反轉後一定是A贏的方案
那其實去掉的是A贏反轉後仍然是A贏的方案
列舉一個B是1的數量i,再列舉A比他多的j
於是就要滿足不等式 A ( i + j ) > B i A-(i+j)>B-i
移項可知 j < = A B 1 j<=A-B-1
不合法的方案數就是 i = 0 B C B i j = 1 a b 1 C A i + j \sum_{i=0}^{B}C_{B}^i*\sum_{j=1}^{a-b-1}C_{A}^{i+j}
變一下就是 i = 0 B C B B i j = 1 a b 1 C A i + j \sum_{i=0}^{B}C_{B}^{B-i}*\sum_{j=1}^{a-b-1}C_{A}^{i+j}
這個柿子實際上等價於前B個選擇了B-i個1,後A個選擇了i+j個1
那麼就是 j = 1 A + B 1 C A + B B + j \sum_{j=1}^{A+B-1} C_{A+B}^{B+j} ,可以知道這種狀態下的答案是
2 A + B + j = 1 A + B 1 C A + B B + j 2 \frac{2^{A+B}+\sum_{j=1}^{A+B-1}C_{A+B}^{B+j}}{2}
擴充套件lucas玩玩
然後就到了卡常階段
發現模數的質因子固定,可以先把階乘預處理
然後根據楊輝三角 組合數只用算一半
然後就可以了…
其實卡了一早上

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define pll pair<long long,long long>
#define pii pair<int,int>
using namespace std;
inline LL read()
{
	LL f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
int stack[20];
inline void write(int x)
{
	if(x<0){putchar('-');x=-x;}
    if(!x){putchar('0');return;}
    int top=0;
    while(x)stack[++top]=x%10,x/=10;
    while(top)putchar(stack[top--]+'0');
}
inline void pr1(int x){write(x);putchar(' ');}
inline void pr2(int x){write(x);putchar('\n');}

int f1[3100000],f2[3100000];
void init(int md1,int md2)
{
	f1[0]=f2[0]=1;
	for(int i=1;i<=md1;i++)f1[i]=(LL)f1[i-1]*((i%2)?i:1)%md1;
	for(int i=1;i<=md2;i++)f2[i]=(LL)f2[i-1]*((i%5)?i:1)%md2;
}
int pow_mod(int a,LL b,int mod)
{
	int ret=1;
	while(b)
	{
		if(b&1)ret=(LL)ret*a%mod;
		a=(LL)a*a%mod;b>>=1;
	}
	return ret;
}
int exgcd(int a,int b,int &x,int &y)
{
	if(a==0)
	{
		x=0;y=1;
		return b;
	}
	else
	{
		int tx,ty;
		int d=exgcd(b%a,a,tx,ty);
		x=ty-(b/a)*tx;
		y=tx;
		return d;
	}
}
int getinv(int a,int mod)
{
	int AA=a,BB=mod,K=1,x,y;
	int d=exgcd(AA,BB,x,y);
	x=((LL)x*(K/d)%(BB/d)+(BB/d))%(BB/d);
	return x;
}
int solve(LL n,int pi,int mod)
{
	if(!n)return 1;
	int ret=1;
	if(pi==2)ret=(LL)ret*f1[mod]%mod;
	else ret=(LL)ret*f2[mod]%mod;
	ret=pow_mod(ret,n/mod,mod);
	if(pi==2)ret=(LL)ret*f1[n%mod]%mod;
	else ret=(LL)ret*f2[n%mod]%mod;
	return (LL)ret*solve(n/pi,pi,mod)%mod;
}
int lim;
int exlucas(LL n,LL m,int pi,int mod,bool tf)
{
	int ok=0;
	for(LL i=n;i;i/=pi)ok+=i/pi;
	for(LL i=m;i;i