1. 程式人生 > >tyvj 4877 組合數 唯一分解定理+字首和優化

tyvj 4877 組合數 唯一分解定理+字首和優化

1.組合數
時間限制:1s
記憶體限制:256MB
【問題描述】
從m個不同元素中,任取n(n≤m)個元素併成一組,叫做從m個不同元素中取出n個元素的一個組合;從m個不同元素中取出n(n≤m)個元素的所有組合的個數,叫做從m個不同元素中取出n個元素的組合數,記作C(m,n)。
你的任務是:計算C(m,n)末尾有幾個0。如C(10,1)=10,末位有一個0。
【輸入】
輸入檔名為zero.in。
第一行一個數T(<=1000),表示資料組數


對於每一組資料:輸入兩個數,m和n
【輸出】
輸出檔名為zero.out。
對於每組資料輸出一行,包含一個數,表示C(m,n)末尾有幾個0
【輸入輸出樣例】
3
10 1
11 7
20 4
1
1
0
【資料說明】
對於30%的資料,1<=m<=20;
對於70%的資料,1<=m<=1000
對於100%的資料,1<=m<=1000000

題解:C(m,n)=m! / ( n! * (m-n)! ), 最終答案會出現0,僅有可能是2*5得到的,也就是說最多有多少對(2,5),用唯一分解定理分解後,將答案儲存下來,維護字首和,下次直接從now+1開始。

總結:這個題wa了一次超時兩次,wa是因為把‘+’打成‘-’l,第一次Tle是因為樸素不加優化,求階乘的2,5個數事重複算了,後來加了優化更慢,多了一個log,其實字首和滿足單調性,只需要記錄now就行了。以後一定要細心些,善於優化。

	#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 1000000
using namespace std;
int T;
struct node
{
	long long re2,re5;
}m1,n1,mn,prime[N],cmt[N];
int date[N],cnt=0,now=0;
void query(int x,int y,node &opt)
{
	opt.re2=opt.re5=0;
	opt.re2+=cmt[x].re2;opt.re5+=cmt[x].re5;
	x++;
	for(int i=x;i<=y;i++)
	{
		int t=i;
	    while(t!=1 && !(t&1))	opt.re2++,t>>=1;
		while(t!=1 && !(t%5))   opt.re5++,t/=5;
		cmt[i].re2=opt.re2;cmt[i].re5=opt.re5;
	}
	now=max(now,y);
}
int main()
{
	int n,m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&m,&n);
		if(m<=now)
		{
			m1.re2=cmt[m].re2;m1.re5=cmt[m].re5;
		}else query(now,m,m1);
		if(n<=now)
		{
		    n1.re2=cmt[n].re2;n1.re5=cmt[n].re5;
		}else query(now,n,n1);
		if(m<=now)
		{
			mn.re2=cmt[m-n].re2;mn.re5=cmt[m-n].re5;
		}else query(now,m-n,mn);
		long long a=m1.re2-(n1.re2+mn.re2),b=m1.re5-(n1.re5+mn.re5);
		printf("%lld\n",min(a,b));
		
	}
	return 0;
}