原题链接:
【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;
}