zerojudge e293. 花開花落,雨初臨

題目在 https://zerojudge.tw/ShowProblem?problemid=e293.

這題目寫了一堆根本也不用看, 簡單的講就是要把5000位的大數, 找出所有小於100的質數.

計算質數的程式可以參考另一篇zerojudge b513. 判斷質數-商競103.小於100的質數有25個, 因為題目的時間限制才0.4秒, 就不要花時間去計算質數, 直接寫在程式裡就好.

我用大數除以每個質數的餘數是否為0, 來檢查是否為質因數. 為了加快速度, 我把大數轉成long long型態來求餘比較快. 大數則放在global 變數也可省去參數的傳遞時間.

string BigNumber; 

long long MOD(long long b){
	int L=BigNumber.length();
	long long  a1=BigNumber[0];
	for(int i=1;i<L;i++){
		a1=a1*10+BigNumber[i];
		if(a1<100000000000000000)
			continue;
		a1=a1%b;
	}
	return a1;
}
C++

現在可以25個質數一個一個檢查. 但是用大數來做25遍太慢了, 一定會TLE. 只有2和5這兩個質數檢查非常快,所以可以分開做. 其他23個質數, 我分成三組來檢查. 第一組是{3,7,11,13,17,19,23,29,31,37},把所有質數乘起來為742073813481, 這數字存於long long不會爆. 然後用上面的方法求餘數, 根據數學原理,如果大數的質因數有在這組質數裡, 那也會存在這餘數裡. 所以就把求得的餘數取代大數來計算就可以很快查出質因數.

void stage1(){
	long long prime[]={3,7,11,13,17,19,23,29,31,37};
	long long b = MOD(742073813481);

	if(b==0){ //剛好這組所有的質數都是質因數
		for(long long p:prime){
			P.insert(p);
		}
		return;
	}
	//每個質數去算是不是質因數
	for(long long p:prime){
		if(b%p==0){
			P.insert(p);
		}
	}
	return;
}
C++

這樣做三次, 第二組我用{41,43,47,53,59,61,67}, 質數相乘為1058967640189, 把第一步程式改一改就好了.

void stage2(){
	long long prime[]={41,43,47,53,59,61,67};
	long long b = MOD(1058967640189);

	if(b==0){ //剛好這組所有的質數都是質因數
		for(long long p:prime){
			P.insert(p);
		}
		return;
	}
	//每個質數去算是不是質因數
	for(long long p:prime){
		if(b%p==0){
			P.insert(p);
		}
	}
}
C++

第三組我就不寫了. 至於為什麼分三組, 不分兩組或四組? 我就測出來分三組最快呀. AC時間僅0.2秒.

完整程式如下.


#include <cstdio>
#include <cstring>
#include <iostream>
#include <cmath>
#include <set>

using namespace std;

string BigNumber;

long long MOD(long long b){
	int L=BigNumber.length();
	long long  a1=BigNumber[0];
	for(int i=1;i<L;i++){
		a1=a1*10+BigNumber[i];
		if(a1<100000000000000000)
			continue;
		a1=a1%b;
	}
	return a1;
}

set <int> P;


void stage1(){
	long long prime[]={3,7,11,13,17,19,23,29,31,37};
	long long b = MOD(742073813481);

	if(b==0){ //剛好這組所有的質數都是質因數
		for(long long p:prime){
			P.insert(p);
		}
		return;
	}
	//每個質數去算是不是質因數
	for(long long p:prime){
		if(b%p==0){
			P.insert(p);
		}
	}
	return;
}

void stage2(){
	long long prime[]={41,43,47,53,59,61,67};
	long long b = MOD(1058967640189);

	if(b==0){ //剛好這組所有的質數都是質因數
		for(long long p:prime){
			P.insert(p);
		}
		return;
	}
	//每個質數去算是不是質因數
	for(long long p:prime){
		if(b%p==0){
			P.insert(p);
		}
	}
}

void stage3(){
	long long prime[]={71,73,79,83,89,97};
	long long b = MOD(293391909323);

	if(b==0){ //剛好這組所有的質數都是質因數
		for(long long p:prime){
			P.insert(p);
		}
		return;
	}
	//每個質數去算是不是質因數
	for(long long p:prime){
		if(b%p==0){
			P.insert(p);
		}
	}
}

char buffer[5001];

int main(){

	int n;
	scanf("%d",&n);
	for(int i=0;i<n;i++)
	{
		scanf("%s",buffer);
		P.clear();
		BigNumber=string(buffer);


		//檢查最後一位, 來確定是否為2或5的倍數
		int check2 = BigNumber[BigNumber.length()-1]-'0';
		if(check2%2==0)
			P.insert(2);
		if(check2==0 || check2==5)
			P.insert(5);

		//字串轉數字
		for(int i=0;i<BigNumber.length();i++){
			BigNumber[i]=BigNumber[i]-'0';
		}

		//分三段檢查質因數
		stage1();
		stage2();
		stage3();


		if(P.size()==0){
			printf("Terrible Silence...\n");
		}else{
			for(int n:P){
				printf("%d ",n);
			}
			printf("\n");
		}
	}
}
C++

Comments

No comments yet. Why don’t you start the discussion?

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *