잡글 가득 블로그
Published 2023. 11. 29. 18:26
Daily PS Comments #2 PS 기록들

매일의 문제 풀이를 기록합니다. 여기서 문제 풀이란, 알고리즘 문제 해결을 의미합니다. 백준/코드포스/앳코더 등의 플랫폼을 이용합니다.

완성도가 높은 글이 아닙니다. 대신 생각의 흐름이 꽤 자세하게 적혀 있을 것 같네요.

 

Special Numbers

링크

mirror 팀에서 cozyyg님의 디버깅 도움으로 AC를 볼 수 있었던 문제입니다. 당시 코드가 굉장히 난잡했어서 깔끔하게 다시 풀어볼 생각입니다.

어제(2023.11.28 - [PS 기록들] - Daily PS Comments #1) 풀었던 문제는 "자릿수 곱이 K 이하인 수의 개수"였고, 이 문제는 "자릿수 곱이 K의 배수인 수의 개수"입니다. 비슷하게 풀어보겠습니다.

 

ㅋㅋㅋㅋ xiaowuc1님이 G1 주신 이유를 알겠네요 이제.. 어제 그 문제랑 똑같이 하되, 곱의 bound를 K로 설정하여 gcd를 관리하면 됩니다.

더보기
#include <bits/stdc++.h>
using namespace std; using ii = pair<int,int>; using ll = long long; using vi = vector<int>;
#define rep(i,a,b) for (auto i = (a); i <= (b); ++i)
#define per(i,a,b) for (auto i = (b); i >= (a); --i)
#define all(x) begin(x), end(x)
#define siz(x) int((x).size())
#define Mup(x,y) x = max(x,y)
#define mup(x,y) x = min(x,y)
#define fi first
#define se second
#define dbg(...) fprintf(stderr,__VA_ARGS__)

#pragma region modnum template from ecnerwala/cp-book
// https://github.com/ecnerwala/cp-book/blob/master/src/modnum.hpp
...
#pragma endregion modnum template
using mint = modnum<1'000'000'007>;

const int N = 23;
int n; ll k;
char s[N];

mint solve(string _s) {
    n = siz(_s);
    rep(i,1,n) s[i] = _s[n-i];
    
    unordered_map<ll,mint> t[N][2], f[N][2]; // k와의 최대공약수
    mint res;
    
    t[0][0][1]=f[0][0][1]=1;
    rep(i,1,n) {
        rep(d,0,9) rep(j,0,1) {
            for (auto &[g,v] : t[i-1][j]) {
                if (d==s[i]-'0') t[i][d>0][gcd(k,g*d)] += v;
            }
            for (auto &[g,v] : f[i-1][j]) {
                f[i][d>0][gcd(k,g*d)] += v;
                if (d<s[i]-'0') t[i][d>0][gcd(k,g*d)] += v;
            }
        }
        if (i < n) res += f[i][1][k];
        else res += t[i][1][k];
    }
    return res;
}

int main() {
    cin >> k;
    
    string L, R;
    cin >> L >> R;
    
    per(i,0,siz(L)-1) {
        if (L[i]=='0') {
            L[i] = '9';
        } else {
            L[i]--;
            break;
        }
    }
    
    while (not empty(L) && L[0]=='0') L.erase(begin(L));
    
    cout << solve(R)-solve(L);
}

 

보일의 법칙

링크

얘도 이제 digit dp 태그입니다.

  • 일단 digit-product의 개수가 얼마 없다는 점을 염두에 둡시다.
    • 2-지수 ≤ 3×18, 3-지수 ≤ 2×18, 5-지수 ≤ 18, 7-지수 ≤ 18
    • 가능한 곱의 개수는 629,856가지입니다.
  • 각 digit-product $M$에 대해 self-product가 $X$ 이하인 수의 개수는,
    • $\lfloor \frac X M \rfloor$ 이하의 digit-product가 $M$인 수의 개수입니다.
  • 정리해봅시다
  • (... 대충 digit dp로 해결하기 위한 많은 시행착오)

 

  • 아닌듯하다
  • 629,856 크기의 digit-dp 집합, $\mathcal{DP}$를 구하는 서브루틴으로 digit dp를 사용했을 가능성이 있습니다.
  • $X$ 이하의 digit-product가 $M$인 수의 개수를 굉장히 빠르게 구하는 방법을 고민해보면 좋을 것 같습니다.

 

  • 생각이 바뀌었습니다.
  • tight와 free를 관리해나가는 것이 digit dp 과정인데,
  • 여기서 free한 부분을 미리 전처리해둔다면 tight를 free만 잘 이용해서 빠르게 구성할 수 있지 않을까요?
  • 대신 top-down을 해줘야 좋을 것 같습니다.

ac! 숏코딩 1등이네요

더보기
#include <bits/stdc++.h>
using namespace std; using ll = long long;
#define rep(i,a,b) for (auto i = (a); i <= (b); ++i)
#define per(i,a,b) for (auto i = (b); i >= (a); --i)
#define siz(x) int((x).size())

const int N = 23;
int n;
char s[N];
unordered_map<ll,ll> f[N];
set<ll> DP;

void precalc() {
    f[0][1]=1;
    rep(i,1,18) rep(d,1,9) {
        for (auto &[j,v] : f[i-1]) {
            if (j*d <= ll(1e18)) {
                f[i][j*d] += v;
                DP.insert(j*d);
            }
        }
    }
}

ll solve(ll x) {
    ll ans = 0;
    for (auto k : DP) {
        string t = to_string(x/k);
        if (t=="0") continue;
        n = siz(t);
        rep(i,1,n) s[i]=t[n-i];
        rep(i,1,n-1) ans += f[i][k];
        per(i,1,n) {
            rep(d,1,min(9,(s[i]-'0'-1))) {
                if (k%d==0) ans += f[i-1][k/d];
            }
            if (s[i]-'0'==0) break;
            if (k%(s[i]-'0')) break;
            k /= s[i]-'0';
            
            if (i==1) ans += k==1;
        }
    }
    return ans;
}

int main() {
    ll A, B;
    cin >> A >> B;
    precalc();
    cout << solve(B)-solve(A-1);
}

'PS 기록들' 카테고리의 다른 글

unordered_map에 사용자 정의 해시 함수 사용하기  (0) 2024.02.05
Daily PS Comments #3  (0) 2023.12.01
Daily PS Comments #1  (3) 2023.11.28
11월의 문제들  (0) 2023.11.08
NYPC 2023 본선 후기  (6) 2023.10.30
profile

잡글 가득 블로그

@도훈.

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!

profile on loading

Loading...