P5440非常详细注释,求助
  • 板块题目总版
  • 楼主Loopbreak
  • 当前回复0
  • 已保存回复0
  • 发布时间2024/6/5 08:52
  • 上次更新2024/6/5 16:10:34
查看原帖
P5440非常详细注释,求助
969943
Loopbreak楼主2024/6/5 08:52
#include <bits/stdc++.h>
using namespace std;

int t;
string s[11];
string path="00000000";  //记录当前枚举结果
int ans = 0;

//普通质数筛
bool isPrame(int n) {
	if (n < 2) return false;
	for (int i = 2; i * i <= n; i++) {
		if (n % i == 0) return false;
	}
	return true;
}

//字符串转整数
int strtoint(string s1) {
	int num = 0;
	for (int i = 0; i < s1.size(); i++) {
		num = num * 10 + (s1[i] - '0');
	}
	return num;
}

//判断年月日合法
bool isRightmonthyear(int year, int month, int days) {
	int m[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31};
	if (month == 2) {  //如果是2月
		if (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)) {  //如果是闰年
			return days <= m[month] + 1;  //是不是在29之内
		} else {
			return days <= m[month];
		}
	} else {
		return days <= m[month];  //如果不是2月,是否在合法范围内
	}
} 	

//判断现枚举结果是否正确
bool isok(string &s1) {
	string year = s1.substr(0,4);  //这三行得年月日
	string month = s1.substr(4,2); 
	string days = s1.substr(6,2);
	if (!isRightmonthyear(strtoint(year), strtoint(month), strtoint(days))) return false;  //日期不合法就不对
	year += month + days; 
	month += days;
	if (isPrame(strtoint(year))) return true; //判断年月日是不是质数
	else return false;
}

//搜索本体,i位置从最后一名开始枚举
void f(string &s1, int i) {
	if (i == 5) {  //如果i到5位置,日已经枚举完了
		int days = strtoint(path.substr(6,2));  //得到日期
		if (days > 31 || days < 2 || !isPrame(days)) return; //先判断日期是否正确,不正确后面就不搜了
	}
	if (i == 3) {  //如果i到3位置,月和日已经枚举完了
		int month = strtoint(path.substr(4,2)); //先看月份
		if (month > 12 || month < 1) return;  //月份不对,后面就不搜了
		month = strtoint(path.substr(4,4));  //再看月+日
		if (!isPrame(month)) return;  //不是质数就不搜了
	}
	if (i < 0) {  //到越界位,所有位置都已经枚举完了
		if (isok(path)) {  //看到年+月+日结果合法
			ans++;  //合法就计数
		}
		return;
	}	
	if (s1[i] != '-') {  //如果当前位是数字
		path[i] = s1[i];  //正常记录
		f(s1, i - 1);  //向左边枚举
	}
	else {
		int flag = 9;  //如果是-,看当前位置是啥位置,确定枚举范围
		if (i <= 3) {  //i小于等于3的话,年份位置都从0-9枚举
			flag = 9;
		} else if (i == 4) {  //i是4的话,月份第一个位,只能枚举0-1
			flag = 1;
		} else if (i == 5) {  //i是5的话,月份第二个位,枚举0-9
			flag = 9;
		} else if (i == 6) {  //i是6的话,日的第一位,枚举0-3
			flag = 3;
		} else {
			flag = 9;   //其它都是枚举0-9
		}
		for (int k = 0; k <= flag; k++) {
			path[i] = char(k + '0');  //枚举结果放进路径中
			f(s1, i - 1);  //向左继续
		}
	}
}

int main() {
	cin >> t;
	for (int i = 0; i < t; i++) {
		cin >> s[i];
		f(s[i],7);  //从最后一位开始搜
		cout << ans << '\n';  //输出答案
		ans = 0;  //答案清零
	}	
	
	return 0;
}

一开始我是从0位置正向去搜,70分,3个TLE,后面想着应先从日期开始判断,所以改成了从右往左去搜索,加了一部分剪枝的逻辑,反而变成0分。没找到具体问题在哪。因此求助各位大佬。

2024/6/5 08:52
加载中...