##20210419 D
题意
给定t个样例,每个样例有两个日期(格式为Y,M,D,表示为年月日),输出两个日期之间的所有日期的年月日组成的字符串中含有"202"的日期的字符串的个数。
思路
- 打表求出2000/01/01与所有日期之间的符合要求的日期的个数a[Y][M][D]。求法:从2000/01/01遍历到9999/12/31。设置一个c记录已经有多少日期符合要求,假设已经遍历到Y/M/D,此时c就是Y/M/D前一天到2000/01/01中所有符合要求的日期的个数。判断当前日期的字符串是否符合要求,符合则c++。此时的c就是2000/01/01到Y/M/D中所有符合要求的日期的个数。
- 对于每个样例都有两个日期Date1:y1,m1,d1和Date2:y2,m2,d2,求这个区间内的符合要求的日期的个数,则我们只需要求a[y2][m2][d2]减去a[Date1前一天]。
- 因为Date1前一天的可能会很难求(比如2021/01/01的前一天是2020/12/31),所以我们转为求cnt=a[y2][m2][d2]-a[y1][m1][d1]。然后判断y1,m1,d1组成的字符串是不是符合要求的字符串:
- 如果符合,说明此时a[y1][m1][d1]比a[Date1]多1,说明多减了一个1,所以cnt加1。
- 如果不符合,说明此时a[y1][m1][d1] == a[Date1],所以c不需要改变。
- 注意:这一题如果暴力,每次都重新求一遍会超时。
代码
#include<iostream>
#include<sstream>
#include<string>
using namespace std;
int a[10000][13][32]; //用于储存打表信息
int main()
{
int y1, y2, m1, m2, d1, d2;
y1 = 2000;
m1 = 1;
d1 = 1;
y2 = 9999;
m2 = 12;
d2 = 31;
int c = 0;
for (int i = y1; i <= y2; i++) //打表
{
int j = 1;
int j1 = 12;
//if (i == y1) j = m1;
//if (i == y2) j1 = m2;
for (; j <= j1; j++)
{
int k = 1;
int k1 = 31;
if (j == 4 || j == 6 || j == 9 || j == 11)
k1 = 30;
if (j == 2)
{
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0)
{
k1 = 29;
}
else
k1 = 28;
}
//if (i == y1 && j == m1) k = d1;
//if (i == y2 && j == m2) k1 = d2;
for (; k <= k1; k++)
{
int p = i * 10000;
p += (j * 100);
p += k;
string b = to_string(p); //将整型转化为字符型
if (b.find("202") != string::npos)//查找是否含有子串"202"
{
c++;
}
a[i][j][k] = c; //记录
}
}
}
int t;
cin >> t;
while (t--)
{
c = 0;
cin >> y1 >> m1 >> d1 >> y2 >> m2 >> d2;
string t;
int p = y1 * 10000;
p += (m1* 100);
p += d1;
string b = to_string(p);
t=to_string(p);
c = a[y2][m2][d2] - a[y1][m1][d1];
if (t.find("202") != string::npos)
{
c++;
}
cout << c << endl;
}
return 0;
}