Author: knishanthreddy
Required Knowledge : Digit Dp
Time Complexity :
Editorialist : knishanthreddy
First, let's understand what makes a Time Code good.
In each Time Code, only the guardians marked with odd digits flip the message. Therefore, for the message to remain unchanged, the total number of odd digits in the sequence must be even.
Since and can be extremely large up to digits, iterating over all Time Codes in the range is impossible.
Hence, we use Digit DP, which allows us to count valid Time Codes digit by digit efficiently.
The DP state is: dppostightparity
pos: current digit index
tight: whether the current prefix matches the upper bound
parity: whether the count of odd digits so far is even or odd
In digit dp, the tight variable will tell if the current digits range is restricted or not. If the current digit's range is not restricted then it will span from to inclusively else it will span from to limitidx (inclusively).
At each position, we try all possible digits from to the allowed limit:
If is odd: it flips the parity.
If is even: parity stays the same.
If tight is and equals the upper limit digit, next state remains tight.
When all digits are processed Base Case:
If parity is even, return good Time Code.
Otherwise, return .
To find the total good Time Codes in range :
Compute countGood: good Time Codes from to .
Compute countGood: good Time Codes from to .
Final answer = countGood− countGood MOD MOD.
// C++
#include <bits/stdc++.h>
using namespace std;
#define endl "\n"
#define all(v) v.begin(),v.end()
#define rall(v) v.rbegin(),v.rend()
#define yes cout << "Yes" << endl
#define no cout << "No" << endl
template<class T>
void input(vector<T> &a) {
for(auto &e:a)
cin >> e;
}
const int M=1e9+7;
int dp[110][2][2];
// fun(index, tight, parity)
int fun(string &num,int idx,bool tight,bool parity) {
if(idx==num.size()) {
return !parity;
}
int &res=dp[idx][tight][parity];
if(res!=-1) return res;
int ub=tight?(num[idx]-'0'):9;
res=0;
for(int i=0;i<=ub;i++) {
res=(res+fun(num,idx+1,tight&(i==ub),parity^(i&1)))%M;
}
return res;
}
//Subract 1 from the big number represented by s
string sub1(string s) {
int n=s.size();
for(int i=n-1;i>=0;i--) {
if(s[i]>'0') {
s[i]--;
break;
}
else s[i]='9';
}
if(s.size()>1 && s[0]=='0') {
return s.substr(1);
}
return s;
}
void solve()
{
string l,r;
cin >> l >> r;
l=sub1(l);
memset(dp, -1, sizeof(dp));
// number of good time codes from 0 to R
int rans=fun(r,0,1,0);
memset(dp,-1,sizeof(dp));
// number of good time codes from 0 to L-1
int lans=fun(l,0,1,0);
cout << (rans-lans+M)%M << endl;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t=1;
cin >> t;
while(t--)
solve();
return 0;
}
//Python
MOD = 10**9 + 7
def count_valid(num):
s = str(num)
n = len(s)
dp = [[[-1 for _ in range(2)] for _ in range(2)] for _ in range(n+1)]
def fun(idx, tight, parity):
if idx == n:
return int(parity == 0)
if dp[idx][tight][parity] != -1:
return dp[idx][tight][parity]
ub = int(s[idx]) if tight else 9
res = 0
for i in range(ub + 1):
res = (res + fun(idx + 1, tight and (i == ub), parity ^ (i & 1))) % MOD
dp[idx][tight][parity] = res
return res
return fun(0, 1, 0)
def main():
t = int(input())
for _ in range(t):
l, r = map(int, input().split())
ans = (count_valid(r) - count_valid(l - 1) + MOD) % MOD
print(ans)
if __name__ == "__main__":
main()