Soluție HackerRank pentru Irresponsible Numbers, subdomeniul Combinatorics, în C++14. Include cerința formatată, exemple, explicația pașilor și cod sursă.
- Problemă: Irresponsible Numbers
- Domeniu: Combinatorics
- Limbaj: C++14
Challenge: Irresponsible Numbers
Subdomeniu: Combinatorics (combinatorics)
Scor cont: 75.0 / 75
Submission status: Accepted
Submission score: 1.0
Submission ID: 464763594
Limbaj: cpp14
Link challenge: https://www.hackerrank.com/challenges/irresponsible-numbers/problem
Cerință
A number, x, is called *irresponsible* when adding x to x+1 requires a *[carry](https://en.wikipedia.org/wiki/Carry_(arithmetic))* operation. For example, 5, 17, and 91 are irresponsible numbers because adding them to 6, 18, and 92 (respectively) requires a carry operation:
- In 5 + (5 + 1) = 5 + 6 = 11, a 1 is carried over into the 10's place.
- In 17 + (17 + 1) = 17 + 18 = 35, a 2 is carried over into the 10's place.
- In 91 + (91 + 1) = 91 + 92 = 183, a 1 is carried over into the 100's place.
You have two integers, x and n. Construct a new number, s, by repeating x a total of n times. For example, if x = 3121 and n = 4, then s = 3121312131213121.
Given x and n, construct s and find all the irreponsible numbers between 1 and s. Then print the number of irresponsible numbers in the aforementioned range; as this number can be quite large, your answer must be modulo 10^9+7.
Input Format
A single line with two space-separated integers denoting the respective values of x and n.
Output Format
Print a single integer denoting the number of irresponsible numbers between 1 and s, modulo 10^9+7.
Constraints
* 1 ≤ x ≤ 10^1,000,000
* 1 ≤ n ≤ 10^18
Subtasks
For 15% of the maximum score:
* 1 ≤ x ≤ 10^6
* n = 1
For 40% of the maximum score:
* 1 ≤ x ≤ 10^1,000,000
* n = 1
Cod sursă
#include <bits/stdc++.h>
using namespace std;
static const long long MOD = 1000000007LL;
struct Mat {
long long a[4][4];
Mat(bool ident = false) {
for (int i = 0; i < 4; ++i)
for (int j = 0; j < 4; ++j)
a[i][j] = (ident && i == j) ? 1 : 0;
}
};
long long modpow(long long x, long long e) {
long long r = 1 % MOD;
x %= MOD;
if (x < 0) x += MOD;
while (e > 0) {
if (e & 1LL) r = (__int128)r * x % MOD;
x = (__int128)x * x % MOD;
e >>= 1LL;
}
return r;
}
Mat mul(const Mat &A, const Mat &B) {
Mat C;
for (int i = 0; i < 4; ++i) {
for (int k = 0; k < 4; ++k) if (A.a[i][k]) {
long long aik = A.a[i][k];
for (int j = 0; j < 4; ++j) if (B.a[k][j]) {
C.a[i][j] = (C.a[i][j] + (__int128)aik * B.a[k][j]) % MOD;
}
}
}
return C;
}
array<long long,4> mulVec(const Mat &A, const array<long long,4> &v) {
array<long long,4> r{0,0,0,0};
for (int i = 0; i < 4; ++i) {
long long s = 0;
for (int j = 0; j < 4; ++j) {
s = (s + (__int128)A.a[i][j] * v[j]) % MOD;
}
r[i] = s;
}
return r;
}
Mat mpow(Mat base, long long exp) {
Mat res(true);
while (exp > 0) {
if (exp & 1LL) res = mul(base, res);
base = mul(base, base);
exp >>= 1LL;
}
return res;
}
Mat transDigit(int c) {
Mat T;
int alpha = (c <= 4) ? 1 : 0;
int beta = (c == 9) ? 1 : 0;
int lessA = min(c, 5);
// state order: EA, EB, LA, LB
// EA' = alpha*EA
T.a[0][0] = alpha;
// EB' = beta*EA + beta*EB
T.a[1][0] = beta;
T.a[1][1] = beta;
// LA' = lessA*EA + 5*LA
T.a[2][0] = lessA;
T.a[2][2] = 5;
// LB' = LA + LB
T.a[3][2] = 1;
T.a[3][3] = 1;
return T;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
string xs;
long long n;
cin >> xs >> n;
// Block transition for one copy of x
Mat block(true);
for (char ch : xs) {
int d = ch - '0';
Mat Td = transDigit(d);
block = mul(Td, block);
}
Mat all = mpow(block, n);
array<long long,4> v0{1,0,0,0}; // equal + in prefix-state
auto vf = mulVec(all, v0);
long long responsible_0_to_S = (vf[0] + vf[1] + vf[2] + vf[3]) % MOD;
long long responsible_pos = (responsible_0_to_S - 1 + MOD) % MOD; // exclude 0
// S = x repeated n times, modulo MOD
long long xv = 0;
for (char ch : xs) xv = (xv * 10 + (ch - '0')) % MOD;
long long p10L = modpow(10, (long long)xs.size());
long long geom;
if (p10L == 1) {
geom = n % MOD;
} else {
long long num = (modpow(p10L, n) - 1 + MOD) % MOD;
long long denInv = modpow((p10L - 1 + MOD) % MOD, MOD - 2);
geom = (__int128)num * denInv % MOD;
}
long long Smod = (__int128)xv * geom % MOD;
long long ans = (Smod - responsible_pos) % MOD;
if (ans < 0) ans += MOD;
cout << ans << '\n';
return 0;
}
