給定日期區間 [y1 m1 d1, y2 m2 d2],計算區間內「月份是素數 且 日期是素數」的天數。年份 1000~2999,含閏年規則。
is_prime[1..31]、month_days[12]、is_leap(y)。m1,d1 到 12 月底。m2,d2。#include <iostream>
using namespace std;
bool prime[32] = {0,0,1,1,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,1,0,1};
int mdays[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
bool is_leap(int y) {
return (y%4==0 && y%100!=0) || y%400==0;
}
int count_in_month(int y, int m, int d_start, int d_end) {
if (!prime[m]) return 0;
int lim = mdays[m];
if (m==2 && is_leap(y)) lim = 29;
d_end = min(d_end, lim);
int cnt = 0;
for (int d = d_start; d <= d_end; ++d)
if (prime[d]) ++cnt;
return cnt;
}
int main() {
int T; cin >> T;
while (T--) {
int y1,m1,d1, y2,m2,d2;
cin >> y1 >> m1 >> d1 >> y2 >> m2 >> d2;
long long ans = 0;
if (y1 == y2) {
if (m1 == m2) ans = count_in_month(y1, m1, d1, d2);
else {
ans += count_in_month(y1, m1, d1, mdays[m1]);
for (int m = m1+1; m < m2; ++m) ans += count_in_month(y1, m, 1, mdays[m]);
ans += count_in_month(y1, m2, 1, d2);
}
} else {
// 首年
ans += count_in_month(y1, m1, d1, mdays[m1]);
for (int m = m1+1; m <= 12; ++m) ans += count_in_month(y1, m, 1, mdays[m]);
// 中間完整年
for (int y = y1+1; y < y2; ++y) ans += is_leap(y) ? 53 : 52;
// 末年
for (int m = 1; m < m2; ++m) ans += count_in_month(y2, m, 1, mdays[m]);
ans += count_in_month(y2, m2, 1, d2);
}
cout << ans << '\n';
}
return 0;
}
count_in_month 可預計算每月素數日期前綴和,O(1) 查詢。ZOJ 3326 是典型的「日期模擬 + 數論篩選」題。關鍵在於識別固定的素數月份/日期集合,利用完整年份固定計數避免逐日遍歷。代碼結構清晰分段處理同年/跨年、首尾年/中間年,邊界條件(閏年 2 月、月份天數)逐一處理,即可準確高效解決。