D2 1000p PalindromeFactory
邮局问题。设Dp[i][j]为从串[i,j]得到回文串的最小步数,然后进行两种操作:删除一个字符、删除两个字符。
int get ( int l, int r )
{
if ( l == r || l == r - 1 && str[l] == str[r] )
return dp[l][r] = 0;
if ( l == r - 1 && str[l] != str[r] )
return dp[l][r] = 1;
if ( dp[l][r] != -1 )
return dp[l][r];
int &res = dp[l][r];
if ( str[l] == str[r] )
res = get ( l + 1, r - 1 );
else
res = get ( l + 1, r - 1 ) + 1;
res = min ( res, get ( l + 1, r ) + 1 );
res = min ( res, get ( l, r - 1 ) + 1 );
return res;
}
public:
int getEditDistance(string initial)
{
str = initial;
memset ( dp, 0xff, sizeof ( dp ) );
int ret = get ( 0, str.size () - 1 );
int i, j, n = str.size ();
for ( i = 0; i < n; i ++ )
for ( j = i + 1; j < n; j ++ )
{
memset ( dp, 0xff, sizeof ( dp ) );
swap ( str[i], str[j] );
ret = min ( ret, get ( 0, n - 1 ) + 1 );
swap ( str[j], str[i] );
}
return ret;
}
}
D1 250p PalindromePhrases
所求解其实就是二进制表达时1的个数。
D1 500p PalindromePhrases
相当有技术含量的DP。
考虑ab, edcba, cd这样的情况,从外向内构造解。
ab和edcba中的ba配对之后,还剩下edc,可以和cd配对。由于只有13个元素,首先考虑到的是bitmask。确定组合后剩下的字符可以做一状态。由于配对有两个方向:如例子中的cd是正方向配对,而edcba是反方向配对,因此将方向作为状态。总状态即为:DP(string 字符串, int 方向, int bitmask)
class PalindromePhrases
{
map < pair < string, int >, long long > m[1 << 13];
vector < string > w[2];
int n;
bool isP ( const string &s ) // palindromic
{
int i = 0, j = s.size () - 1;
while ( i < j && s[i] == s[j] )
i ++, j --;
return i >= j;
}
int getPrefix ( const string &a, const string &b )
{
int i, ret = 0;
for ( i = 0; i < a.size () && i < b.size (); i ++ )
{
if ( a[i] == b[i] )
ret ++;
else
break;
}
return ret;
}
long long get ( const string &ex, int r, int used )
{
//printf ( "%s %d %d/n", ex.c_str (), r, used );
if ( used == ( 1 << n ) - 1 )
{
//printf ( "%s %d %d/n", ex.c_str (), r, used );
//printf ( "back %d/n/n", isP ( ex ) );
return isP ( ex );
}
pair < string, int > key = MP ( ex, r );
if ( m[used].count ( key ) )
{
//printf ( "%s %d %d/n", ex.c_str (), r, used );
//printf ( "%lld/n/n", m[used][key] );
return m[used][key];
}
long long int &res = m[used][key];
res = 0;
if ( isP ( ex ) )
res = 1;
int i;
for ( i = 0; i < n; i ++ )
if ( ( ( 1 << i ) & used ) == 0 )
{
int wlen = w[r][i].size ();
int plen = getPrefix ( w[r][i], ex );
if ( plen != wlen && plen != ex.size () )
continue;
int t;
if ( plen == wlen )
{
res += ( t = get ( ex.substr ( plen ), r, ( 1 << i ) | used ) );
}
else
{
res += ( t = get ( w[r][i].substr ( plen ), 1 - r,
( 1 << i ) | used ) );
}
}
//printf ( "%s %d %d/n", ex.c_str (), r, used );
//printf ( "%d/n/n", res );
return res;
}
}