# Prime Number# Prefix Sum# Modulo Operation

f479 - 質數成長

🔗 前往 ZeroJudge 原題

題目描述

題目描述了一種植物的成長模式,其每天的成長速度由連續質數列表決定。給定第 N 天和節數 K,要求輸出植物第 K 節對應的字母(A, B, 或 C)。如果 K 超出第 N 天的節數,則輸出 #。字母的分配方式是按照質數列表的餘數來決定:餘數為 1 時輸出 A,餘數為 2 時輸出 B,餘數為 0 時輸出 C。

解題思路

首先,需要預先計算出前 N 個質數的和,這可以使用埃拉托斯特尼篩法生成質數,然後使用前綴和來快速計算。接著,判斷 K 是否超出第 N 天的節數。如果 K 超出,則輸出 #。否則,計算 K 對應的字母。具體來說,找到前綴和中大於等於 K 的第一個質數和,然後計算 K 與前一個質數和的差的餘數,根據餘數輸出 A、B 或 C。

複雜度分析

  • 時間複雜度: O(N + Q),其中 N 是質數列表的最大長度(在本例中為 110000),Q 是查詢次數(<= 10000)。埃拉托斯特尼篩法的時間複雜度為 O(N log log N),前綴和計算為 O(N),每次查詢的時間複雜度為 O(log N) (二分查找),但由於題目 N 的範圍不大,可以優化為線性查找,因此整體查詢時間複雜度為 O(Q)。
  • 空間複雜度: O(N),用於存儲質數列表和前綴和。

程式碼

#pragma GCC optimize("Ofast,unroll-loops,no-stack-protector,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
#include <stdio.h>
int pt[110001],it;
int adp[110001],n,k;
char p[110001]={1};
inline int read(){
	int a(0);
	char c('0');
	while(c>='0'){
		a=(a<<3)+(a<<1)+c-'0';
		c=getchar_unlocked();
	}
	return a;
}
int main(){
	for(int i=2;i<=332;++i)
		for(int j=i+i;j<=110000;j+=i)
			p[j]=1;
	for(int i=0;i<=110000;++i)
		if(p[i]==0){
			pt[it]=i;
			if(it>0)
				adp[it]=pt[it]+adp[it-1];
			else
				adp[it]=pt[it];
			++it;
		}
	while(n=read()){
		k=read();
		if(adp[n-1]<k)
			putchar_unlocked('#');
		else{
			int it2=0;
			while(adp[it2]<k)
				++it2;
			int total=(k-adp[it2-1])%3;
			if(total==1)
				putchar_unlocked('A');
			else if(total==2)
				putchar_unlocked('B');
			else
				putchar_unlocked('C');
		}
		putchar_unlocked('\n');
	}
}

Discussion