読者です 読者をやめる 読者になる 読者になる

srupのメモ帳

競プロで解いた問題や勉強したことを記録していくメモ帳

SRM 692 div2 medium Dubs

問題

問題概要

LとRが与えられる。LとRの間に、2桁以上で、最後の2桁の数字が同じで数がいくつあるか。

解法

桁dpで解いた。dp[i][j][k] := 整数p(L, R)を考えた時に、i番目の桁まで考えて、j=1の時は考えている数がp未満であることが決定していて、j=0の時はp以下である。 kは前回の数字 としてdpで数えあげていった。漸化式はコード参照。0の時も数えあげているが、与えられているLRがどちも0より大きいので問題ない。
これより単純な解法がある。下2桁が同じ数字ということは、下2桁が、00,11,...99であればよい。つまり、下2桁が、00から99で10個存在する。この周期性を利用して、 周期がいくつあるかをx/100で計算してその数だけまず存在する。あとは、残りの部分を全探索でどれだけあるかを探す。

ミス

2桁以上を、2つ以上の数字を含んでいると思って、めんどくさい桁dpを書いていた。

コード

桁dp

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(n);i++)

//dp[i][j][k]
//整数pを考えた時に、i番目の桁まで考えて、j=1の時は考えている数がp未満であることが決定していて、j=0の時はp以下である。
//kは前回の数字
long long dp[15][2][10];

class Dubs{
public:

    long long slove(string s){
        rep(i, 15)rep(j, 2)rep(k, 10)dp[i][j][k] = 0;
        dp[0][0][0] = 1;

        ll ret  = 0;
        rep(i, s.size()){
            rep(j, 2){
                int lim;
                if(j == 1) lim = 9;//i桁目までですでに未満が決まっていればi+1桁目の数字は何でもよい
                else lim = s[i] - '0';
       
                rep(k, 10)rep(l, lim + 1){
                    if(i < s.size() - 1){
                        dp[i + 1][j || (l < lim)][l] += dp[i][j][k];
                    }else{
                        if(k == l){//下二桁が同じ数(00もカウントしてしまっているが大丈夫)
                            dp[i + 1][j || (l < lim)][l] += dp[i][j][k];
                            ret += dp[i][j][k];//答えに加える
                        }else{//下二桁が異なる数
                            dp[i + 1][j || (l < lim)][l] += dp[i][j][k];
                        }
                    }
                }            
            }
        }

        return ret;
    }


    long long count(long long L, long long R){
        L--;
        string SL = to_string(L), SR = to_string(R);
        return slove(SR) - slove(SL);
    }
};

周期性を利用して計算

#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cstdio>

using namespace std;
typedef long long ll;
#define rep(i,n) for(int i=0;i<(n);i++)

class Dubs{
public:
    ll cnt(ll x){
        ll sum = 0;
        //10 (= 00, 11, .., 99)
        sum += 10 * (x / 100);
        int t = x % 100;
        for (int i = 0; i <= t; ++i){
            //下2桁が一致
            if(i % 10 == i / 10){
                sum++;
            }
        }
        return sum;
    }

    long long count(long long L, long long R){
        return cnt(R) - cnt(L - 1);
    }
};