luogu P5440 【XR-2】奇迹

原题链接:

【XR-2】奇迹 - 洛谷https://www.luogu.com.cn/problem/P5440

题目背景

相信奇迹的人,本身就和奇迹一样了不起。——笛亚 《星游记》

题目描述

我们称一个日期为一个八位数,第 1~4 位构成年,第 5~6 位构成月,第 7~8 位构成日,不足位数用 0 补足。同时,要求日期所代表的这一天真实存在,且年的范围为 1~9999。

出现奇迹的日期都存在相同的特点:由“日”组成的两位数,由“月+日”组成的四位数,由“年+月+日”组成的八位数均为质数。但并不是所有存在这样特点的日期都一定会出现奇迹。

现在,你得到了一个可能会出现奇迹的日期,然而不幸的是这个日期却是残缺的,八位中可能有若干位无法确定。你需要知道这个日期有多少种可能,这样你才能做好充足的准备去迎接奇迹的到来。

输入格式

本题有多组数据。

第一行一个正整数 T,表示数据组数。

接下来的 T 行,每行一个八位字符串。其中第 i 位如果为 -,则表示日期的第 i 位无法确定,否则表示日期的第 i 位为字符串中第 i 位上的数字。

输出格式

对每组数据,一行一个整数,表示答案。

输入输出样例

输入 #1复制

2
53-7-3-7
20190629

输出 #1复制

6
0

说明/提示

【样例 11 说明】

53-7-3-7 的 6 种可能的日期如下:

53070307
53070317
53170307
53370307
53570317
53770307

【数据规模与约定】

一共 10 个测试点,记 cc 为八位字符串中 - 的个数。

对前 9 个测试点,在第 ii 个测试点中保证c=i−1。

对100% 的数据保证1≤T≤10。

Solution:

        吐了,日常因为check写错点小细节调一小时.一道dfs题,但是如果从前到后暴力枚举每一位的话那必然tle,8^10 = 1073741824并且对于10^8的素数无法用筛法选择,如果直接素数判断也就是最坏计算次数可能到数十万亿,估摸得跑一小时.于是本着正难则反的思想,我们倒着搜,搜2位对日进行一次判断,如果不合法或不是素数就return,月份也如此,这样就不会t了(实际要跑三秒但是这题开了四秒)

ACcode:

#include<bits/stdc++.h>
using namespace std;
int t,ans;
char now[10];
bool isprime(int x)
{
	if(x==0||x==1)	return 0;
	if(x==2||x==3||x==5||x==7)	return 1;
	if(x%6!=1&&x%6!=5)	return 0;
	int num = sqrt(x);
	for(int i = 5;i<=num;i+=6)
		if(x%i==0||x%(i+2)==0)
			return 0;
	return 1;
}
bool check_day()
{
	int day = (now[7]-'0')*10+(now[8]-'0');
	if(day>31)	return 0;
	if(!isprime(day))	return 0;
	return 1;
 }
bool check_month()
{
	int day = (now[5]-'0')*1000+(now[6]-'0')*100+(now[7]-'0')*10+(now[8]-'0');
	int month = (now[5]-'0')*10+(now[6]-'0');
	if(month>12)	return 0;
	int dayday = (now[7]-'0')*10+(now[8]-'0');
	if(month==2&&dayday>29)	return 0;
	if((month==4||month==6||month==9||month==11)&&(dayday>30))	return 0;
	if(!isprime(day))	return 0;
	return 1;
}
void check_year()
{
	int day = (now[1]-'0')*10000000+(now[2]-'0')*1000000+(now[3]-'0')*100000+(now[4]-'0')*10000+(now[5]-'0')*1000+(now[6]-'0')*100+(now[7]-'0')*10+(now[8]-'0');
	int year = (now[1]-'0')*1000+(now[2]-'0')*100+(now[3]-'0')*10+(now[4]-'0');
	int month = (now[5]-'0')*10+(now[6]-'0');
	int dayday = (now[7]-'0')*10+(now[8]-'0');
	if(year==0||month==0||dayday==0)	return;
	if(month==2&&(year%4!=0||(year%100==0&&(year%400!=0)))&&dayday>28)	return;
	if(isprime(day))
		ans++;
	return;
}
void dfs(int step)
{
	if(step==0){
		check_year();
		return;
	}
	if(step==6)	
		if(!check_day())	
			return;
	if(step==4)	
		if(!check_month())	
			return;
	if(now[step]!='-')	dfs(step-1);
	else
		for(int i = 0;i<=9;++i)
		{
			now[step] = i+'0';
			dfs(step-1);
			now[step] = '-';
		}
}
int main()
{
	cin>>t;
	while(t--)
	{
		ans = 0;
		cin>>(now+1);
		int n = strlen(now+1);
		if(n<8)
			for(int i = n+1;i<=8;++i)
				now[i] = '0';
		dfs(8);
		cout<<ans<<endl;
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值