• 【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<<'
    ';
        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<<'
    ';
        return 0;
    }

    QwQ

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

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

  • 相关阅读:
    es6新增特性,数组的操作方法
    导航钩子有哪几种,如何将数据传入下一个点击的路由页面
    父组件如何获取子组件数据,子组件如何获取父组件数据,父子组件如何传值
    watch和computed的区别
    vue页面中定时器的使用
    table表格,顶端对齐
    计算机组成原理8-FPGA、ASIC、TPU、虚拟机
    vue中使用socket连接后台
    计算机组成原理7-CISC和RISC、GPU
    计算机组成原理6-流水线、多发射和超标量、SIMD、异常
  • 原文地址:https://www.cnblogs.com/gwj1314/p/9444632.html
Copyright © 2020-2023  润新知