Блог пользователя kstheking

Автор kstheking, история, 6 лет назад, По-английски

We had this question on our Internship test, and I couldn't figure out how to do it, help please

Given a string s and a number p find number of unique special strings that can be formed using the given string
A special string is a permutation of string made from a subsequence of s, whose sum of ASCII values of its characters is divisible by p
Example: s = "ab", p = "2"
answer = 1
all possible unique strings = "a","b","ab", "ba"
respective sums = 97, 98, 195, 195
reason: since there is only one number (98) which is divisible by 2 so total answer = 1
Constraints: |s| <= 20 and 1 <= p <= 200
print the answer modulo 1000000007

  • Проголосовать: нравится
  • -12
  • Проголосовать: не нравится

»
6 лет назад, скрыть # |
← Rev. 3  
Проголосовать: нравится 0 Проголосовать: не нравится

You can try 3D DP where :
1st state represents the current index of the string
2nd state represents the current sum of ASCII values of the subsequence chosen (It ranges from 122 to 122*n)
3rd state represents the current modulo of the subsequence ASCII sum with p
This should work because the time complexity would be n*(122*n)*p where n is |s|.
UPD : Didn't took care of the unique sunstring thing, Since the string length is <=20, backtracking approach might work out considering all the possibilities of the subsequences.

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +3 Проголосовать: не нравится

was it on campus or off?? (OFF-TOPIC)

»
6 лет назад, скрыть # |
 
Проголосовать: нравится -10 Проголосовать: не нравится

iterate though all mask from 1 to (1<<n) special string => sum of ascii values of all character in the current mask should be divisible by p(can be checked) unique string => maintain trie or set to check this all possible combination using current mask => let frequency be c1,c2....c26 (assuming alphabet size = 26) ans = (c1+c2+.....)! / c1! * c2 ! ........ c26!

»
6 лет назад, скрыть # |
 
Проголосовать: нравится -13 Проголосовать: не нравится

We can find all 2^n strings and then count sum of ASCII values of character in each string. If sum is divisible by p then add the value of all possible permutation of that string to result. I think this will fit in given TL

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +19 Проголосовать: не нравится

You can store frequency of each character then solve it using dp with 3 states(current character, sum with mod p, current length of the string).

»
6 лет назад, скрыть # |
← Rev. 3  
Проголосовать: нравится +1 Проголосовать: не нравится

Try all possible subsequences and if subsequence X is good then add its number of unique permutations (Factorial of length divided by factorials of character's frequencies) to the answer, since its all possible permutation will be the answer as well.

»
6 лет назад, скрыть # |
 
Проголосовать: нравится +1 Проголосовать: не нравится

Since |s| <= 20, there would be (2^20, i.e. 10^6) combinations, so just brute force every, if any subsequence is divisible by p, do some combinatrics(can be done in O(len)) to find unique permuations.

»
6 лет назад, скрыть # |
← Rev. 3  
Проголосовать: нравится 0 Проголосовать: не нравится

Just backtrack to find every possible sums. To know unique strings whose sum is divisible by p, you just have to know how many characters it took to build this sum. Like here = "abc" and p=2, we can find 97, 98, 99, 195, 196, 197, 294 and 0 if we backtrack all possible sums. We'll just ignore 0 here. So here 98,196 and 294 are divisible by 2. 98 took 1, 196 took 2 and 294 took 3 characters . So the answer is 1! + 2! + 3! = 9

»
6 лет назад, скрыть # |
← Rev. 2  
Проголосовать: нравится 0 Проголосовать: не нравится

Since $$$|S|$$$ is quite small try generating all subsets and find the answer using combinatorics. Let's say current subset chooses some indices where these characters occurs -> "aaaeedd"(their order doesn't matter). If their $$$sum$$$ is divisible by $$$p$$$ then we can permute them in $$$7! / (3! * 2! * 2!)$$$ ways and add them to our answer. take care not to overcount since we need unique strings (e.g. $$$S$$$ = "abab", so choosing subset {0, 1} {0, 3}, {2, 3} are all same and should be counted only once).

PS: the above solution of mine seems correct to me but if you find anything wrong then please let me know. Thanks.

»
4 года назад, скрыть # |
 
Проголосовать: нравится 0 Проголосовать: не нравится

I think this should work...

#include <bits/stdc++.h>
#define int long long
using namespace std;

int mod = 1e9 + 7;
vector<int> fac(22,0), freq(26,0);
int dp[202][202][22];

void precompute()
{
    fac[0] = fac[1] = 1;
    for(int i=2; i<=21; i++)
    {
        fac[i] = (fac[i-1] * i) % mod;
    }
}

int solve(int idx, int sum, int siz, string &s, int &p)
{
    if (idx == s.size()) return 0;
    if (dp[idx][sum][siz] != -1) return dp[idx][sum][siz];
    int ans = solve(idx + 1, sum, siz, s, p) % mod;
    int x = 0;
    for(int i=1; i<=freq[s[idx]- 'a']; i++)
    {
        x = (sum + i * (s[idx]))%p;
        if (x == 0) ans = (ans + ((fac[siz + i] / fac[i]) % mod) + solve(idx + 1, 0, siz + i, s, p) ) % mod;
        else ans = (ans + solve(idx + 1, x, siz + i, s, p)) % mod;
    }
    return dp[idx][sum][siz] = ans % mod;
}

int32_t main()
{
    precompute();
    string s; cin >> s;
    int p; cin >> p;
    memset(dp,-1,sizeof(dp));
    string x;
    for(int i=0; i<s.size(); i++)
    {
        if (freq[s[i] - 'a'] == 0) x.push_back(s[i]);
        freq[s[i] - 'a']++;
    }
    cout << solve(0, 0, 0, x, p);
}