1、contact
这题估计是丢俺老脸的题,因为俺就直接枚举了。唯一的trick是对于 01, 001这样的字符串,计算hash值的时候,需要记得转换为 101, 1001这样的形式,不然肯定就混淆了,所以直接上代码吧,应该好懂。
-
/*
-
ID:fairyroad
-
LANG:C++
-
TASK:contact
-
*/
-
#include <fstream>
-
#include <string>
-
#include <algorithm>
-
using namespace std ;
-
-
ifstream fin ( "contact.in" ) ;
-
ofstream fout ( "contact.out" ) ;
-
-
#define MAXNUM 16385 // 1<<14 + 1
-
size_t A, B, N ;
-
string s ;
-
-
struct Sequence {
-
int cnt ;
-
string str ;
-
Sequence ( ) : cnt ( 0 ), str ( "" ) { }
-
Sequence ( int c, string s ) : cnt (c ), str (s ) { }
-
bool operator > ( const Sequence & other ) const {
-
if (cnt > other. cnt ) return true ;
-
if (cnt == other. cnt ) {
-
if (str. length ( ) < other. str. length ( ) ) return true ;
-
else if (str. length ( ) == other. str. length ( ) ) return str < other. str ;
-
else return false ;
-
}
-
return false ;
-
}
-
} ;
-
-
Sequence hash [MAXNUM ] ;
-
-
int main ( )
-
{
-
fin >> A >> B >> N ;
-
string line ;
-
while (getline (fin, line ) )
-
s + =line ;
-
-
int num ;
-
size_t j, k ;
-
-
for ( size_t i = A ; i <= B ; ++i )
-
{
-
for (j = 0 ; j + i <= s. size ( ) ; ++j )
-
{
-
num = 1 ; // 注意这里,关键就在这里了
-
for (k = j ; k - j < i ; ++k )
-
{
-
num <<= 1 ;
-
if (s [k ] == '1' ) num + = 1 ;
-
}
-
-
if ( !hash [num ]. cnt )
-
{
-
hash [num ]. cnt = 1 ;
-
hash [num ]. str = string (s, j, i ) ;
-
}
-
else
-
hash [num ]. cnt ++ ;
-
}
-
}
-
-
sort (hash, hash + MAXNUM, greater <Sequence > ( ) ) ; // 可以在前面的循环中就建立一个大小为N的堆
-
-
int linenum = 1, precnt = hash [ 0 ]. cnt ;
-
fout << hash [ 0 ]. cnt << '\n' << hash [ 0 ]. str ;
-
size_t i, outline = 1 ;
-
-
for (i = 1 ; i < MAXNUM ; ++i )
-
{
-
if ( !hash [i ]. cnt ) break ;
-
-
if (hash [i ]. cnt == precnt )
-
{
-
if (linenum < 6 )
-
{
-
linenum ++ ;
-
fout << ' ' << hash [i ]. str ;
-
}
-
else
-
{
-
linenum = 1 ;
-
fout << '\n' << hash [i ]. str ;
-
}
-
}
-
else
-
{
-
if (outline == N ) break ;
-
precnt = hash [i ]. cnt ;
-
fout << '\n' << hash [i ]. cnt << '\n' << hash [i ]. str ;
-
linenum = 1 ;
-
outline ++ ;
-
}
-
}
-
-
fout << endl ;
-
return 0 ;
-
}
2、Stamps
这题我比较喜欢,我想凡是做过ACM的多少都有点似曾相识的感觉,因为这题多少可以算是背包问题的变种,而背包问题几乎是ACM必修课了,下面直接给出DP公式:
f(m) =
1. dp(m) if dp(m) is set
2. min(dp(m-s(i)) + 1, for i in [0, n)
因为2中有一个循环,所以复杂度是O(N*M)。
-
/*
-
ID:fairyroad
-
LANG:C++
-
TASK:stamps
-
*/
-
#include <fstream>
-
using namespace std ;
-
-
ifstream fin ( "stamps.in" ) ;
-
ofstream fout ( "stamps.out" ) ;
-
-
int k, n ; // 可以使用的邮票的张数,邮票种类
-
int s [ 50 ] ;
-
int dp [ 10000 * 200 + 1 ] ;
-
-
int main ( )
-
{
-
fin >> k >> n ;
-
int i, min, curr = 0, tmp ;
-
for (i = 0 ;i < n ; ++i )
-
{
-
fin >> s [i ] ;
-
dp [s [i ] ] = 1 ; // 这些面值可以直接获取
-
}
-
-
while ( true )
-
{
-
++curr ;
-
if (dp [curr ] ! = 0 ) continue ; // 注意curr是从1开始升上去的
-
-
min = k + 1 ;
-
for ( i = 0 ; i < n ; ++i )
-
{
-
tmp = curr -s [i ] ;
-
if (tmp <= 0 ) continue ; // 输入的邮票面值集合不一定是从小到大排好序的
-
if (dp [tmp ] + 1 < min )
-
min = dp [curr -s [i ] ] + 1 ;
-
}
-
-
if (min > k ) break ;
-
-
dp [curr ] = min ;
-
}
-
-
fout << curr - 1 << endl ;
-
return 0 ;
-
}
老生常谈,大多数情况下,动态规划是缩时利器,虽然空间上会打点折扣。而DP的关键就是要写出那个递推公式。一句八卦就是,如果你熟练掌握了动态规划,大多数情况下,面试中你可以藐视众多面试题~