【NOIP2016】【Luogu2010】回文日期(枚举,可以计算出部分值)

problem
  • 指定两个日期(8位数字描述)
  • 问这之间有多少日期表示是回文串(包含这两个日期本身)
solution1
  • 枚举所有日期
  • 回文串判断
//O((t-s)*360)
#include<iostream>
#include<algorithm>
#include<string>
using namespace std;

int days[15] = {0,31,28,31,30,31,30,31,31,30,31,30,31};

bool check(string x){
    for(int i = 0; i < 4; i++)
        if(x[i] != x[7-i])return false;
    return true;
}
int getnum(string x, int l, int r){
    int ans = 0;
    for(int i = l; i <= r; i++)
        ans = ans*10+x[i]-'0';
    return ans;
}
string getstring(int i, int j, int k){
    string ans = "";
    ans += i/1000%10+'0';
    ans += i/100%10+'0';
    ans += i/10%10+'0';
    ans += i%10+'0';
    if(j < 10)ans +="0", ans += j+'0';
    else ans += j/10%10+'0', ans += j%10+'0';
    if(k < 10)ans +="0", ans += k+'0';
    else ans += k/10%10+'0', ans += k%10+'0';
    return ans;
}
bool is_run(int x){
    return (x%4==0&&x%100!=0)||(x%400==0);
}

int main(){
    string s, t;
    cin>>s>>t;
    int ans = 0;
    int s1 = getnum(s,0,3), t1 = getnum(t,0,3);
    int s2 = getnum(s,4,5), t2 = getnum(t,4,5);
    int s3 = getnum(s,6,7), t3 = getnum(t,6,7);
    if(s1 == t1){
        if(is_run(s1))days[2]++;
        if(s2 == t2){
            for(int k = s3; k <= t3; k++)
                if(check(getstring(s1,s2,k)))ans++;
        }else{
            for(int k = s3; k <= days[s2]; k++)
                if(check(getstring(s1,s2,k)))ans++;
            for(int j = s2+1; j < t2; j++)
                for(int k = 1; k <= days[j]; k++)
                    if(check(getstring(s1,j,k)))ans++;
            for(int k = 1; k <= t3; k++)
                if(check(getstring(s1,t2,k)))ans++;
        }
        if(is_run(s1))days[2]--;
    }else{
        if(is_run(s1))days[2]++;
        for(int k = s3; k <= days[s2]; k++)
            if(check(getstring(s1,s2,k)))ans++;
        for(int j = s2+1; j <= 12; j++)
            for(int k = 1; k <= days[j]; k++)
                if(check(getstring(s1,j,k)))ans++;
        if(is_run(s1))days[2]--;
        for(int i = s1+1; i < t1; i++){
            if(is_run(i))days[2]++;
            for(int j = 1; j <= 12; j++){
                for(int k = 1; k <= days[j]; k++){
                    if(check(getstring(i,j,k)))ans++;
                }
            }
            if(is_run(i))days[2]--;
        }
        if(is_run(t1))days[2]++;
        for(int j = 1; j < t2; j++)
            for(int k = 1; k <= days[j]; k++)
                if(check(getstring(t1,j,k)))ans++;
        for(int k = 1; k <= t3; k++)
            if(check(getstring(t1,t2,k)))ans++;
        if(is_run(t1))days[2]--;
    }
    cout<<ans<<'\n';
    return 0;
}
solution2

你真的想像上面一样写???
1、枚举所有回文串(即枚举月份和日期,可以反过来就算出年份【因为答案是回文串啊】),在范围内就累加答案。
2、二月不需要判断闰年:二月只能是闰年才会成立,不可能是平年。因为当二月是平年时,有28天,就是0228,整个日期是82200228,但是8220是闰年,,hh。

//O(360)
#include<iostream>
using namespace std;
int days[15] = {0,31,29,31,30,31,30,31,31,30,31,30,31};
int main(){
    int s, t;
    cin>>s>>t;
    int ans = 0;
    for(int j = 1; j <= 12; j++){
        for(int k = 1; k <= days[j]; k++){
            int i = (k%10*1000)+(k/10*100)+(j%10*10)+(j/10);//算出回文情况下的前4位
            int data = i*10000+j*100+k;
            if(data<s || data > t)continue;
            ans++;
        }
    }
    cout<<ans<<'\n';
    return 0;
}
QwQ

吐槽:是一个枚举题。难点(代码复杂度)在于枚举所有的日期,因为要对是否为开始的月份日期,结束的月份日期进行分类讨论,代码就变长了,也更加容易出错(虽然我一遍就对了没调试,但是写了大约50mins,,如果哪里炸了就更惨,复杂度也不优。)。。。

角度?:
1、枚举题目给定的范围,判断是否为答案,累加ans。(模拟)
2、枚举答案的可能情况即所有可行解,判断是否在题目范围内,累加ans。
有什么区别么额,,qaq。
还是有一点的吧?雾。。。
这样吧。。 & #$%^&*(@!%^
3、关键可能是?通过枚举一部分数据来计算出另一部分数据,减少了枚举的量,优化了效率。
4、尝试从不同角度去思考不同的枚举方式,可能代码复杂度会有降低。
大致。

转载于:https://www.cnblogs.com/gwj1314/p/9444632.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值