XORCOUNT - Editorial

PROBLEM LINK:

Practice
Contest: Division 1
Contest: Division 2

Setter:
Tester: Trung Nguyen
Editorialist: Taranpreet Singh

DIFFICULTY

Medium-Hard

PREREQUISITES

Combinatorics (Maybe Dynamic Programming)

PROBLEM

Given five integers L, R, A, B, K, find the number of arrays containing K integers such that all values lie in range [L, R] and bitwise XOR of all elements is in range [A, B]

Do note that the order of elements matter in distinguishing one array from other.

QUICK EXPLANATION

  • Reducing XOR sum in range [A, B] into two subproblems where XOR sum must be up to B.
  • Fixing most significant bit b where there exist an element in array such that it’s significant bits up to b-th bit differ from both L and R.
  • Considering all possible number of elements having bits up to b-th bit same bits L, R, or b-th bit different, we can compute the XOR sum of significant bits and the number of permutations of such groups.
  • For less significant bits, it is easy to count the number of candidates for each element, depending on whether bits up to b-th bit match L, R or neither, and take required powers of number of candidates.

EXPLANATION

Since number of arrays with XOR in range [A, B] is same as number of arrays with XOR strictly less than B+1 less number of arrays with XOR strictly up to A, So we can directly focus on counting number of K-length arrays with elements range [L, R] and XOR < B

Let’s handle the arrays where all elements are either L or R separately. Assuming k occurrences of L, thus K-k occurrences of R, if the xor of these values is < B, all permutation of k occurrences of L and K-k occurrences of R contribute to arrays (There are \binom{K}{k} of them).

So now, for remaining arrays, we are guaranteed that there exists at least one element in array (say X) such that L < X < R.

Let’s fix the bit b where considering significant bits up to b-th bit of L, R and all values in array, there exists a value X in array such that significant bits up to b-th bit of X differs from both L and R. We will count all such arrays separately for each fixed bit and then take total. It is easy to prove that there is no double-counting of arrays here.

Considering l = L/2^b, r = R/2^b, bSig = B/2^b and l_2 = L \bmod 2^b, r_2 = R \bmod 2^b and bRem = B \bmod 2^b, l, r and bSig holds significant b bits of L, R and B, and l_2, r_2 and bRem holds remaining bits of L, R and B.

Since all elements in array had first b-1 bits same as either L or R, the first b bits of any element in array can only be one among \{l, l+1, r-1, r \} (l+1 happens only when l has last bit off, similarly, r-1 is allowed only when r has last bit on.)

Let’s consider all possible tuples (a, b, c, d) such that

  • a+b+c+d = K
  • Exactly a values in array have significant bits up to b bits same as l
  • Exactly b values in array have significant bits up to b bits same as l+1 (b = 0 if l \bmod 2 = 1, all elements must have first b bits as l)
  • Exactly c values in array have significant bits up to b bits same as r-1 (c = 0 if r \bmod 2 = 0, all elements must have first b bits as r)
  • Exactly d values in array have significant bits up to b bits same as r
  • b+c > 0 (If b+c = 0, then there’s no element in array having significant bits up to b bits different from both L and R)

For each tuple, we can easily find xor sum of bits up to b-th bit of elements in array (It only depends upon a, b, c and d.) If it’s strictly greater than bSig, the xor sum would exceed B irrespective of remaining bits, so we can skip.

We can also find the number of permutations of 4 values l, l+1, r-1 and r as multinomial coefficient. For remaining bits, there are three options.

  • Element have significant bits up to b-th bit same as l (group a)
    These elements can have remaining bits in range [l_2, 2^b-1]
  • Element have significant bits up to b-th bit same as r (group d)
    These elements can have remaining bits in range [0, r_2]
  • Remaining elements (group b and c)
    These elements can have remaining bits in range [0, 2^b-1]

We can now take powers of the number of candidates for each class and multiply (dependent events) to get the required number of elements.

One last thing to consider is when significant bits up to b-th bit of generated XOR sum for some tuple is exactly same as significant bits up to b-th bit of B. In that case, one of the element in group b or c can be set to make any required XOR sum for remaining b bits. There are bRem candidates for XOR sum of last b bits, and one of the element is determined by XOR sum, we only need to count the ways to fix remaining values.

I have intentionally used variable naming in editorial. It is consistent with the solution attached, for easy reference.

It is also possible to kick out one K factor here by noticing that only b+c and the parity of b and c matters in a tuple, so we can directly iterate over that and multiply ways by the number of (b, c) with given sum and parities, but it wasn’t required to get accepted.

More efficient solutions are also possible. What’s the fastest you can get? Can you beat this?

PS: There’s one different (slower) approach with dynamic programming where you fix tuple (b, lo, hi, tight) denoting the number of ways that upto b-th bit, exactly lo elements have bits same as L, exactly hi elements have bits same as R and the tight denotes whether based on bits upto current bit, the XOR sum is equal to B or smaller.

TIME COMPLEXITY

For each bit, we need to iterate over tuple (a, b, c, d) with sum K, leading to K^3 tuples for each bit, leading to time complexity O(K^3*log(B))

SOLUTIONS

Setter's Solution
#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define pii pair<int, int>
#define F first
#define S second
#define all(c) ((c).begin()), ((c).end())
#define sz(x) ((int)(x).size())
#define ld long double

template<class T,class U>
ostream& operator<<(ostream& os,const pair<T,U>& p){
	os<<"("<<p.first<<", "<<p.second<<")";
	return os;
}

template<class T>
ostream& operator <<(ostream& os,const vector<T>& v){
	os<<"{";
	for(int i = 0;i < (int)v.size(); i++){
		if(i)os<<", ";
		os<<v[i];
	}
	os<<"}";
	return os;
}

#ifdef LOCAL
#define cerr cout
#else
#endif

#define TRACE

#ifdef TRACE
#define trace(...) __f(#__VA_ARGS__, __VA_ARGS__)
template <typename Arg1>
void __f(const char* name, Arg1&& arg1){
	cerr << name << " : " << arg1 << std::endl;
}
template <typename Arg1, typename... Args>
void __f(const char* names, Arg1&& arg1, Args&&... args){
	const char* comma = strchr(names + 1, ',');cerr.write(names, comma - names) << " : " << arg1<<" | ";__f(comma+1, args...);
}
#else
#define trace(...)
#endif

long long readInt(long long l,long long r,char endd){
	long long x=0;
	int cnt=0;
	int fi=-1;
	bool is_neg=false;
	while(true){
		char g=getchar();
		if(g=='-'){
			assert(fi==-1);
			is_neg=true;
			continue;
		}
		if('0'<=g && g<='9'){
			x*=10;
			x+=g-'0';
			if(cnt==0){
				fi=g-'0';
			}
			cnt++;
			assert(fi!=0 || cnt==1);
			assert(fi!=0 || is_neg==false);
 
			assert(!(cnt>19 || ( cnt==19 && fi>1) ));
		} else if(g==endd){
			if(is_neg){
				x= -x;
			}
			if(!(l<=x && x<=r))cerr<<l<<"<="<<x<<"<="<<r<<endl;
			assert(l<=x && x<=r);
			return x;
		} else {
			assert(false);
		}
	}
}
string readString(int l,int r,char endd){
	string ret="";
	int cnt=0;
	while(true){
		char g=getchar();
		assert(g!=-1);
		if(g==endd){
			break;
		}
		cnt++;
		ret+=g;
	}
	assert(l<=cnt && cnt<=r);
	return ret;
}
long long readIntSp(long long l,long long r){
	return readInt(l,r,' ');
}
long long readIntLn(long long l,long long r){
	return readInt(l,r,'\n');
}
string readStringLn(int l,int r){
	return readString(l,r,'\n');
}
string readStringSp(int l,int r){
	return readString(l,r,' ');
}
template<class T>
vector<T> readVector(int n, long long l, long long r){
	vector<T> ret(n);
	for(int i = 0; i < n; i++){
	    ret[i] = i == n - 1 ? readIntLn(l, r) : readIntSp(l, r);
	}
	return ret;
}

const int mod = 998244353;
inline int add(int x, int y){ x += y; if(x >= mod) x -= mod; return x;}
inline int sub(int x, int y){ x -= y; if(x < 0) x += mod; return x;}
inline int mul(int x, int y){ return (x * 1ll * y) % mod;}
inline int powr(int a, ll b){
	int x = 1 % mod;
	while(b){
		if(b & 1) x = mul(x, a);
		a = mul(a, a);
		b >>= 1;
	}
	return x;
}
inline int inv(int a){ return powr(a, mod - 2);}

const int N = 105;
const int LN = 60;

int C[N][N];
int powers[3][N];

ll getxor(ll x, int k){
	return k & 1 ? x : 0;
}

// O(K^3 logB)
int f(int k, ll L, ll R, ll B){
	// all either equal to L or R
	int ret = 0;
	for(int i = 0; i <= k; i++){
	    if((getxor(L, i) ^ getxor(R, k - i)) < B) ret = add(ret, C[k][i]);
	}
	// largest bit for which prefix > L's prefix, < R's prefix
	for(int i = LN - 2; i >= 0; i--){
	    ll l = L >> i, r = R >> i, bb = B >> i;
	    ll rem_b = B & ((1LL << i) - 1);

	    ll l2 = L & ((1LL << i) - 1);
	    ll r2 = R & ((1LL << i) - 1);
	    int down_l = ((1LL << i) - l2) % mod;
	    int down_r = (r2 + 1) % mod;
	    int others = (1LL << i) % mod;
	    if(r - l <= 1) continue;
	    int bmax = l % 2 == 0 ? k : 0;
	    int cmax = r % 2 == 1 ? k : 0;
	    vector<int> v = {down_l, down_r, others};

	    for(int i = 0; i < 3; i++){
	        powers[i][0] = 1;
	        for(int j = 1; j <= k; j++) powers[i][j] = mul(powers[i][j - 1], v[i]);
	    }
	    for(int a = 0; a <= k; a++){
	        for(int b = 0; a + b <= k && b <= bmax; b++){
	            for(int c = 0; a + b + c <= k && c <= cmax; c++){
	                if(b + c == 0) continue;
	                int d = k - (a + b + c);
	                ll up_xor = getxor(l, a) ^ getxor(l + 1, b) ^ getxor(r - 1, c) ^ getxor(r, d);
	                if(up_xor > bb) continue;
	                int ways = mul(C[k][a], mul(C[k - a][b], C[k - a - b][c]));
	                int total_ways = 0;
	                if(up_xor < bb) total_ways = mul(ways, mul(powers[0][a], mul(powers[1][d], powers[2][b + c])));
	                else total_ways = mul(rem_b % mod, mul(ways, mul(powers[0][a], mul(powers[1][d], powers[2][b + c - 1]))));
	                ret = add(ret, total_ways);
	            }
	        }
	    }
	}
	return ret;
}

int f(int k, ll L, ll R, ll A, ll B){
	if(L == R){
	    ll x = 0;
	    if(k & 1) x = L;
	    if(x >= A && x <= B) return 1;
	    return 0;
	}
	return sub(f(k, L, R, B + 1), f(k, L, R, A));
}
const ll MAXV = (1LL << 60) - 1;
int main(){
	for(int i = 0; i < N; i++){
	    C[i][0] = 1;
	    for(int j = 1; j <= i; j++){
	        C[i][j] = add(C[i - 1][j - 1], C[i - 1][j]);
	    }
	}
	int t = readIntLn(1, 10);
	while(t--){
	    ll L = readIntSp(0, MAXV), R = readIntSp(0, MAXV), A = readIntSp(0, MAXV), B = readIntSp(0, MAXV);
	    int k = readIntLn(1, 50);
	    assert(L <= R && A <= B);
	    cout << f(k, L, R, A, B) << endl;
	}
}
Tester's Solution
#pragma GCC optimize("Ofast")
#include <bits/stdc++.h>
using namespace std;
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/rope>
using namespace __gnu_pbds;
using namespace __gnu_cxx;
#ifndef rd
#define trace(...)
#define endl '\n'
#endif
#define pb push_back
#define fi first
#define se second
#define int long long
typedef long long ll;
typedef long double f80;
#define double long double
#define pii pair<int,int>
#define pll pair<ll,ll>
#define sz(x) ((long long)x.size())
#define fr(a,b,c) for(int a=b; a<=c; a++)
#define rep(a,b,c) for(int a=b; a<c; a++)
#define trav(a,x) for(auto &a:x)
#define all(con) con.begin(),con.end()
const ll infl=0x3f3f3f3f3f3f3f3fLL;
const int infi=0x3f3f3f3f;
const int mod=998244353;
//const int mod=1000000007;
typedef vector<int> vi;
typedef vector<ll> vl;

typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> oset;
auto clk=clock();
mt19937_64 rang(chrono::high_resolution_clock::now().time_since_epoch().count());
int rng(int lim) {
	uniform_int_distribution<int> uid(0,lim-1);
	return uid(rang);
}
int powm(int a, int b) {
	int res=1;
	while(b) {
		if(b&1)
			res=(res*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return res;
}

long long readInt(long long l,long long r,char endd){
	long long x=0;
	int cnt=0;
	int fi=-1;
	bool is_neg=false;
	while(true){
		char g=getchar();
		if(g=='-'){
			assert(fi==-1);
			is_neg=true;
			continue;
		}
		if('0'<=g && g<='9'){
			x*=10;
			x+=g-'0';
			if(cnt==0){
				fi=g-'0';
			}
			cnt++;
			assert(fi!=0 || cnt==1);
			assert(fi!=0 || is_neg==false);

			assert(!(cnt>19 || ( cnt==19 && fi>1) ));
		} else if(g==endd){
			if(is_neg){
				x= -x;
			}
			assert(l<=x && x<=r);
			return x;
		} else {
			assert(false);
		}
	}
}
string readString(int l,int r,char endd){
	string ret="";
	int cnt=0;
	while(true){
		char g=getchar();
		assert(g!=-1);
		if(g==endd){
			break;
		}
		cnt++;
		ret+=g;
	}
	assert(l<=cnt && cnt<=r);
	return ret;
}
long long readIntSp(long long l,long long r){
	return readInt(l,r,' ');
}
long long readIntLn(long long l,long long r){
	return readInt(l,r,'\n');
}
string readStringLn(int l,int r){
	return readString(l,r,'\n');
}
string readStringSp(int l,int r){
	return readString(l,r,' ');
}


int p2=(1LL<<60)-1,l,r,n;
int dp[61][51][51][2];
int ncr[105][105],p2k[105];
int solve(int a) {
	memset(dp,0,sizeof(dp));
	int star=-1;
	if(l==r) {
		int pp=(n&1)*l;
		if(l<=a)
			return 1;
		return 0;
	}
	for(int i=59; i>=0; i--) {
		if((l^r)>>i) {
			star=i;
			int pp=(n&1)*(l>>(i+1));
			int bb=a>>(i+1);
			if(pp>bb)
				return 0;
			if(pp==bb) {
				int aa=(a>>i)&1;
				for(int i=0; i<=n; i++) {
					if(i&1) {
						if(aa)
							dp[star][i][n-i][0]=ncr[n][i];
					} else {
						if(aa==0)
							dp[star][i][n-i][0]=ncr[n][i];
						else
							dp[star][i][n-i][1]=ncr[n][i];
					}
				}
			} else {
				for(int i=0; i<=n; i++)
					dp[star][i][n-i][1]=ncr[n][i];
			}
			break;
		}
	}
	for(int i=star-1; i>=0; i--) {
		for(int j=0; j<=n; j++)
			for(int k=0; k+j<=n; k++) {
				int rem=n-k-j;
				int lim=j*((r>>i)&1);
				int nr=j-lim;
				for(int p=0; p<=lim; p++,nr++) {
					int lim2=((l>>i)&1)*k;
					int nl=lim2;
					for(int m=k; m>=lim2; m--,nl++) {
						int mul=ncr[j][p]*ncr[k][m];
						if(rem==0) {
							mul%=mod;
							int parhere=(p^m)&1;
							if(parhere<((a>>i)&1))
								dp[i][nr][nl][1]=(dp[i][nr][nl][1]+((dp[i+1][j][k][0]+dp[i+1][j][k][1])*mul))%mod;
							else if(parhere==((a>>i)&1)) {
								dp[i][nr][nl][1]=(dp[i][nr][nl][1]+(dp[i+1][j][k][1]*mul))%mod;
								dp[i][nr][nl][0]=(dp[i][nr][nl][0]+(dp[i+1][j][k][0]*mul))%mod;
							} else
								dp[i][nr][nl][1]=(dp[i][nr][nl][1]+(dp[i+1][j][k][1]*mul))%mod;
						} else {
							mul=(mul*p2k[rem-1])%mod;
							if(((a>>i)&1)) {
								dp[i][nr][nl][1]=(dp[i][nr][nl][1]+((dp[i+1][j][k][0]+2*dp[i+1][j][k][1])*mul))%mod;
								dp[i][nr][nl][0]=(dp[i][nr][nl][0]+(dp[i+1][j][k][0]*mul))%mod;
							} else {
								dp[i][nr][nl][1]=(dp[i][nr][nl][1]+(2*dp[i+1][j][k][1]*mul))%mod;
								dp[i][nr][nl][0]=(dp[i][nr][nl][0]+(dp[i+1][j][k][0]*mul))%mod;
							}
						}
					}
				}
			}
	}
	int ans=0;
	fr(i,0,n)
		fr(j,0,n)
			ans=(ans+dp[0][i][j][0]+dp[0][i][j][1])%mod;
	return ans;
}
void solve() {
//	l=0,r=p2;
	l=readIntSp(0,p2),r=readIntSp(l,p2);
	int a=readIntSp(0,p2),b=readIntSp(a,p2);
//	int a,b;
//	a=p2;
//	b=p2;
	n=readIntLn(1,50);
//	n=50;
	int ans=solve(b);
//	trace(ans,b);
	if(a)
		ans=(ans-solve(a-1)+mod)%mod;
	cout<<ans<<endl;
}

signed main() {
	p2k[0]=1;
	fr(i,1,100)
		p2k[i]=(p2k[i-1]*2)%mod;
	ncr[0][0]=1;
	fr(i,1,100) {
		ncr[i][0]=1;
		fr(j,1,i)
			ncr[i][j]=(ncr[i-1][j]+ncr[i-1][j-1])%mod;
	}
	ios_base::sync_with_stdio(0),cin.tie(0);
	srand(chrono::high_resolution_clock::now().time_since_epoch().count());
	cout<<fixed<<setprecision(7);
	int t=readIntLn(1,10);
//	int t=10;
	auto clk=clock();
//	cin>>t;
	fr(i,1,t)
		solve();
	assert(getchar()==EOF);
#ifdef rd
	cerr<<endl<<endl<<endl<<"Time Elapsed: "<<((double)(clock()-clk))/CLOCKS_PER_SEC<<endl;
#endif
}
Editorialist's Solution
import java.util.*;
import java.io.*;
class XORCOUNT{
	//SOLUTION BEGIN
	final int BIT = 61;
	final long MOD = 998244353;
	void pre() throws Exception{}
	void solve(int TC) throws Exception{
	    long L = nl(), R = nl(), A = nl(), B = nl();
	int K = ni();
	int[][] C = new int[1+K][1+K];
	C[0][0] = 1;
	for(int i = 1; i<= K; i++){
		C[i][0] = 1;
		for(int j = 1; j<= i; j++){
		C[i][j] = C[i-1][j]+C[i-1][j-1];
		if(C[i][j] >= MOD)C[i][j] -= MOD;
		}
	}
	
	if(L == R){
		long xor = (K%2)*L;
		if(A <= xor  && xor <=B)pn(1);
		else pn(0);
		return;
	}
	
	long ans = (compute(C, L, R, K, B+1)+MOD-compute(C, L, R, K, A))%MOD;
	pn(ans);
	}
	//xor of k occurrences of x.
	long getXor(long x, long k){
	return (k&1)*x;
	}
	long compute(int[][] C, long L, long R, int K, long B){
	long ans = 0;
	//All values are either L, or R
	for(int k = 0; k <= K; k++){
		//Say k occurrences of L and K-k occurrences of R
		if((getXor(L, k)^getXor(R, K-k)) < B)
		ans = add(ans, C[K][k]);
	}
	for(int bit = BIT-1; bit >= 0; bit--){
		long l = L>>bit, r = R>>bit, bNow = B>>bit, bRem = B&((1L<<bit)-1);
		//There exists a number X in array such that (L>>bit) < (X >> bit) < (R>>bit)
		if(r-l <= 1)continue;
		
		long l2 = L&((1L<<bit)-1), r2 = R&((1L<<bit)-1);//last b bits of $L$ and $R$
		long lo_candidates = ((1L<<bit)-l2)%MOD;	//lower group (a)
		long hi_candidates = (r2+1)%MOD;		//upper group (d)
		long other_candidates = (1L<<bit)%MOD;	//free group (b+c)
		
		long[] val = new long[]{lo_candidates, hi_candidates, other_candidates};
		long[][] pow = new long[3][1+K];
		for(int i = 0; i< 3; i++){
		pow[i][0] = 1;
		for(int k = 1; k <= K; k++)pow[i][k] = mul(pow[i][k-1], val[i]);
		}
		
		//Handling condition where l has b-th bit on, or r has b-th bit off
		int bmax = (l&1) == 1?0:K, cmax = (r&1) == 0?0:K;
		for(int a = 0; a<= K; a++){
		for(int b = 0; a+b <= K && b <= bmax; b++){
			for(int c = 0; a+b+c <= K && c <= cmax; c++){
			int d = K-(a+b+c);
			if(b+c == 0)continue;//If b+c == 0, no element X satisfy (L>>bit) < (X >> bit) < (R>>bit)
			
			long xor_now = getXor(l, a)^getXor(l+1, b)^getXor(r-1, c)^getXor(r, d);
			if(xor_now > bNow)continue;//xor > B irrespective of remaining bits.
			
			long ways = mul(C[K][a], mul(C[K-a][b], C[K-a-b][c]));		//Permutation, just based on bits up to b-th bit
			long ways2 = mul(pow[0][a], mul(pow[1][d], pow[2][b+c-1]));	//Ways of fixing remaining b bits for each group. Note that one element from (b+c) is skipped
			
			if(xor_now < bNow)ans = add(ans, mul(other_candidates, mul(ways, ways2)));//xor < B irrespective of remaining bits, so considering all ways for the skipped element
			else ans = add(ans, mul(bRem%MOD, mul(ways, ways2)));//xor can be >=  B, so we decide last element in free group to make xor < B
			}
		}
		}
	}
	return ans;
	}
	long add(long a, long b){
	a += b;
	return a >= MOD?a-MOD:a;
	}
	long mul(long a, long b){
	if(a >= MOD)a %= MOD;
	if(b >= MOD)b %= MOD;
	return a*b%MOD;
	}
	
	void dbg(Object... o){System.err.println(Arrays.deepToString(o));}
	//SOLUTION END
	void hold(boolean b)throws Exception{if(!b)throw new Exception("Hold right there, Sparky!");}
	static boolean multipleTC = true;
	FastReader in;PrintWriter out;
	void run() throws Exception{
	    in = new FastReader();
	    out = new PrintWriter(System.out);
	    //Solution Credits: Taranpreet Singh
	    int T = (multipleTC)?ni():1;
	    pre();for(int t = 1; t<= T; t++)solve(t);
	    out.flush();
	    out.close();
	}
	public static void main(String[] args) throws Exception{
	    new XORCOUNT().run();
	}
	int bit(long n){return (n==0)?0:(1+bit(n&(n-1)));}
	void p(Object o){out.print(o);}
	void pn(Object o){out.println(o);}
	void pni(Object o){out.println(o);out.flush();}
	String n()throws Exception{return in.next();}
	String nln()throws Exception{return in.nextLine();}
	int ni()throws Exception{return Integer.parseInt(in.next());}
	long nl()throws Exception{return Long.parseLong(in.next());}
	double nd()throws Exception{return Double.parseDouble(in.next());}

	class FastReader{
	    BufferedReader br;
	    StringTokenizer st;
	    public FastReader(){
	        br = new BufferedReader(new InputStreamReader(System.in));
	    }

	    public FastReader(String s) throws Exception{
	        br = new BufferedReader(new FileReader(s));
	    }

	    String next() throws Exception{
	        while (st == null || !st.hasMoreElements()){
	            try{
	                st = new StringTokenizer(br.readLine());
	            }catch (IOException  e){
	                throw new Exception(e.toString());
	            }
	        }
	        return st.nextToken();
	    }

	    String nextLine() throws Exception{
	        String str = "";
	        try{   
	            str = br.readLine();
	        }catch (IOException e){
	            throw new Exception(e.toString());
	        }  
	        return str;
	    }
	}
}

VIDEO EDITORIAL:

Feel free to share your approach. Suggestions are welcomed as always. :slight_smile:

1 Like