Do not forget to take answer modulo 1,000,000,007.
This DP opened up a new dimension for me. The way we look at solving the DP, heres the cool blog by Vexorian
That we need to count the unique subsequences makes things more complicated because we don't want to count duplicates. To work around this, imagine if we were generating the subsequence and then checking if it is possible to find the subsequence in the string.
Imagine we had a subsequence like "(())()" to check if it is a possible subsequence of s we can begin with its first character "(" and find the left-most position j of "(" in s. Then we continue with the second character which is another "(" and find the left-most position after j that is equal to "(" and so and so until we find all the characters in the subsequence in s or until we run out of positions of s
Dynamic programming
In order to use that logic we would have to generate the subsequence step by step. We begin with an empty string and add "(" or ")" in each step, making sure the subsequence is a correct bracket sequence. We also start with a pointer i to a position in s. When we decide to add a "(" to the subsequence, find the smallest position j greater than or equal to i such that s[j] is "(" then move i to j+1. The same with ")". This would look like a backtracking problem.
We can find a dynamic programming approach by noticing that, in order to make sure the subsequence is a valid bracket sequence, we don't need to remember all the contents of the subsequence, just the number of open brackets. So if the characters currently in the subsequence are: "(()((()", then we only need to know there are 3 open bracket. With this in mind we can create a function f(o,i) that will give us the number of ways to complete a subsequence with o open brackets if we can only use characters in s after index i:
- When o=0, we already found a valid subsequence, because all the brackets are closed.
- We can also decide to add a "(" to the subsequence. Find the left-most position j such that: s[j] is "(" and j≥i. Then we can continue adding characters to the subsequence but this time the number of open brackets increased and i changed to j+1: There are f(⊕1,j+1) ways to complete the subsequence after this step.
- If o≠0 we can decide to close a bracket by adding a ")" character. Find the smallest j such that s[j] is ")" and j≥i. This adds f(o−1,j+1) new ways to complete the subsequence.
- The sum of those 3 cases is the result. In some cases, the "(" or ")" characters cannot be found in the string so we ignore them.
The function f(o,i) has O(n2) possible states. In each state, we might need an O(n) loop to find the smallest position of the "(" and ")" characters. The total time complexity is O(n3), very appropriate for n≤100.
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int dp[110][110];
int getnext(string s,int idx,int ch,int l)
{
int i;
for(i=idx;i<l;i++)
{
if(s[i]==ch)
{
return i;
}
}
return i;
}
int solve(int op,int idx,string s,int l)
{
//cout<<"op idx "<<op<<" "<<idx<<endl;
if(idx==l)
{
if(op==0)
return 1;
return 0;
}
if(dp[op][idx]!=-1)
return dp[op][idx];
int ret=0;
if(op==0)
ret++;
int poso=getnext(s,idx,'(',l);
// cout<<"for idx "<<idx<<" "<<poso<<endl;
if(poso<l)
{
// cout<<"caleed "<<endl;
ret+=solve(op+1,poso+1,s,l);
ret%=mod;
}
int pose=getnext(s,idx,')',l);
// cout<<" of idx "<<idx<<" "<<pose<<endl;
if(op>=1 && pose<l)
{
// cout<<"clled close "<<endl;
ret+=solve(op-1,pose+1,s,l);
ret%=mod;
}
dp[op][idx]=ret;
return ret;
}
int count(string s)
{
int l=s.length();
memset(dp,-1,sizeof(dp));
int idx=0;
while(s[idx]!='(')
idx++;
if(idx==l)
return 0;
return solve(1,idx+1,s,l);
}#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
#define ll long long int
int dp[110][110];
int getnext(string s,int idx,int ch,int l)
{
int i;
for(i=idx;i<l;i++)
{
if(s[i]==ch)
{
return i;
}
}
return i;
}
int solve(int op,int idx,string s,int l)
{
//cout<<"op idx "<<op<<" "<<idx<<endl;
if(idx==l)
{
if(op==0)
return 1;
return 0;
}
if(dp[op][idx]!=-1)
return dp[op][idx];
int ret=0;
if(op==0)
ret++;
int poso=getnext(s,idx,'(',l);
// cout<<"for idx "<<idx<<" "<<poso<<endl;
if(poso<l)
{
// cout<<"caleed "<<endl;
ret+=solve(op+1,poso+1,s,l);
ret%=mod;
}
int pose=getnext(s,idx,')',l);
// cout<<" of idx "<<idx<<" "<<pose<<endl;
if(op>=1 && pose<l)
{
// cout<<"clled close "<<endl;
ret+=solve(op-1,pose+1,s,l);
ret%=mod;
}
dp[op][idx]=ret;
return ret;
}
int count(string s)
{
int l=s.length();
memset(dp,-1,sizeof(dp));
int idx=0;
while(s[idx]!='(')
idx++;
if(idx==l)
return 0;
return solve(1,idx+1,s,l);
}
|
No comments:
Post a Comment