1 m个数填充n个space,每个数至少出现一次。
代码 1
#include <iostream>
using namespace std;
typedef long long int ll;
ll a[101][101];
#define MOD 1000000007
int dp(int n,int m){
if(n<m||m==0) return 0;
a[0][0]=1;
for(int i=1;i<=n;i++){//n spaces
for(int j=1;j<=i;j++){
a[i][j]=a[i-1][j-1]*(m+1-j);
if(j!=i) a[i][j]+=a[i-1][j]*j;
a[i][j]%=MOD;
}
}
return a[n][m];
}
int main(){
int n;cin>>n;
for(int i=1;i<=n;i++){
int n,m;cin>>m>>n;
cout<<"Case #"<<i<<": "<<dp(n,m)<<endl;
}
return 0;
}
求n-楼梯数列的第k项,用括号序列表示:
楼梯序列的性质:任意一点左边的上楼梯次数>=下楼梯次数(或左括号个数>=右括号个数). 且2*n长的括号序列个数=C(2*n,n)-C(2*n,n-1)
代码 2
#include <iostream>
#include <string.h>
using namespace std;
typedef long long int ll;
ll a[201][201];
ll getNum(int k,int n){
if(k<0||k>n) return 0;
int maxN=(n-k)/2; // max value of cnt('(') - cnt(')'): k+x <= n-x, x=(n-k)/2;
//ll a[n+1][maxN+1];
for(int i=0;i<=maxN;i++) a[0][i]=0;
a[0][k]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=maxN;j++){
a[i][j]=0;
if(j<maxN) a[i][j]+=a[i-1][j+1];// (
if(j>0) a[i][j]+=a[i-1][j-1]; // )
///a[i][j]%=MOD; cannot %mod
}
}
return a[n][0];
}
string getKStr(int n,ll k){
int lst=0; //当前左括号-右括号的值
ll number=k;
char s[201];
for(int i=0;i<2*n;i++){
s[i]='(';
ll cnt=getNum(lst+1, 2*n-1-i);
if(number<=cnt) {
lst=lst+1;
}else{
number-=cnt;
s[i]=')';
cnt=getNum(lst-1,2*n-1-i);
if(number<cnt) return ""; // no solution
lst=lst-1;
}
}
s[2*n]=0;
return string(s);
}
int main(){
int n;
for(int i=0;i<n;i++){
ll N,k;cin>>N>>k;
cout<<"Case #"<<i+1<<": "<<getKStr(N,k)<<endl;
}
return 0;
}
非降序列计数:
状态:a[len]={ <lst, cnt>},长度为len的序列,其中最后一项(也是最大的)值为lst的个数=cnt
when num[i]=x come,
for len:= i to 0:
for j:=minn to maxn:
if x>=j: a[len][j] => a[len+1][x].
二维状态 a[len][lst] = cnt
代码 3
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#define MAXN 1000
#define MINN -9999999
typedef pair<int,int> Pair;
#define rep(i,n) for(int i=0;i<(int)(n);i++)
int dp( int num[], int n ){
vector<Pair> a[MAXN];
rep( i, n+1 ) a[i].clear();
a[0].push_back( Pair( MINN, 1 ) );
rep( i, n ){
int x=num[i];
for( int m = i ; m >= 0; m-- ){
int cnt=0;
rep( j, a[m].size() ){
Pair &p = a[m][j];
if( p.first <= x ){
cnt += p.second;
}
else break;
}
if( cnt == 0 ) continue;
int idx = 0;
bool tag = false;
rep( j, a[m+1].size() ){
Pair &p = a[m+1][j];//@error: a[m][j] mistaked and array overflow
if( p.first == x ) {
p.second += cnt;
tag = true;
break;
}
else if(p.first > x ){
a[m+1].insert( a[m+1].begin() + j, Pair( x, cnt ) );
tag = true;
break;
}
}
if( !tag ) a[m+1].insert( a[m+1].end(), Pair( x, cnt ) );
}
}
int cnt = 0;
int i = n;
while( i >= 0 && a[i].empty() ) i -- ;
if( i>=0 )
rep( j, a[i].size() )
cnt += a[i][j].second;
cout<<"longest array:"<<i<<endl;
return cnt;
}
int main(){
int num[10] = { 2, 1, 3, 0, -1, 2, 3, 1 };
cout<<dp( num, 8 )<<endl;
while( true ){
int n; cin>>n;
if( !n ) break;
for(int i = 0; i < n; i ++ ) cin>>num[i];
cout<<dp( num, n )<<endl;
}
return 0;
}
找最长递增序列长度:
关键是 iterator it=lower_bound(a.begin(),a.end(),x),it指向第一个大于等于x的元素。(bigger_bound指向最后一个大于等于x。。)
代码 4
#include <iostream>
#include <vector>
#include <map>
using namespace std;
#define MAXN 1000
#define MINN -9999999
typedef pair<int,int> Pair;
#define rep(i,n) for(int i=0;i<(int)(n);i++)
int dp(int num[], int n){
vector<int> a;
typedef vector<int>::iterator IT;
int len = 0;
rep( i, n ){
int x = num[i];
IT idx = lower_bound( a.begin(), a.end(), x );
if( idx == a.end() ) a.insert( a.end(), x );
else *idx = x;
}
return a.size();
}
int main(){
int a[10] = {1,3,-2,5,-4,9,1,-1,10};
cout<<dp(a,9)<<endl;
return 0;
}
最长非降子序列的枚举:找到所有最长递增子序列
首先有a=vector<vector< pair<int, vector<vector<int>>> >>,保存的是len长度,所有最后一个值和相应子序列集合。
递推方程:
a[len]={ <lst,{子序列} > },
a[len] . append(x) => a[len+1]
其实枚举的是每一个num[i]=x,前面接
代码 5
该代码存在一个逻辑疏忽! 当扫描到 num[i]=x时,没必要枚举所有的len=1~i,a[len] =》 a[len+1],
只需要找到第一个a[len],其中包含有小于等于x的pair<int,vector<vector<int>>>就可以了。把该小于等于x的串添加上x,再插入到a[len+1]就完成了。
时间复杂度: n*(log n + m )= O(n*n) 不是下面代码的O(n^3)
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
#include <map>
typedef pair< int, vector<vector<int> > > Pair;
struct cmper{
bool operator () ( const Pair &a, const Pair &b ){
return a.first <= b.first;
}
}cmp;
struct arrsort{
bool operator () ( const vector<int> &a, const vector<int> &b ){
for( int i = 0 ; i < a.size() && i < b.size() ; i++ ){
if( a[i] != b[i] ) return a[i] <= b[i];
}
return a.size() <= b.size();
}
}acmp;
void dp(int num[], int n){
vector<vector<Pair> > a( n + 1, vector<Pair> () );
a[0].push_back( Pair( -9999, vector<vector<int> >( 1, vector<int>( 1, -9999 ) ) ) );
for( int i = 0; i < n; i ++ ){
int x = num[i];
for( int j = i; j >= 0; j--){
// append a[j],x to a[j+1]
vector<vector<int> > ss;
for( int k = 0; k < a[j].size(); k++ ){
if( a[j][k].first > x ) break;
vector<vector<int> > &t=a[j][k].second;
for (int l=0; l < t.size(); l++ ){
vector<int> tmp = t[l];
tmp.push_back( x );
ss.push_back( tmp );
}
}
if( ss.empty() ) continue;
vector<Pair>::iterator it = lower_bound( a[j+1].begin(), a[j+1].end(), Pair( x, vector<vector<int> >() ) );
if( it != a[j+1].end() && it->first == x ){
vector<vector<int> > &s = it->second;
s.insert( s.end(), ss.begin(), ss.end() );
}
else a[j+1].insert( it, Pair( x, ss ) );
<span style="white-space:pre"> </span> break; //@attention: @error: here since a[j+1] already contains (x,ss), a[k<j+1] should not contains(x,ss) anymore.
}
}
vector<vector<int> > tt;
int i = n;
while( i>=0 && a[i].empty() ) i--;
if( i>=0 ){
for( int j = 0 ; j < a[i].size(); j++ ){
vector<vector<int> > &s=a[i][j].second;
tt.insert( tt.end(), s.begin(), s.end() );
}
sort( tt.begin(), tt.end(), acmp );
for( int k = 0; k < tt.size(); k++ ){
// skip tt[k][0] = -9999
for( int l = 1; l < tt[k].size(); l++ ){
cout<< tt[k][l]<<" ";
}
cout<<endl;
}
}
}
int main(){
int num[10] = { 1, 3, 2, 15, 10 };
dp( num, 5 );
return 0;
}
最短编辑距离:
len[0][i]=i; len[j][0]=j; //init
i=1 to n: j=1 to m:
len[i][j]= a[i-1]==b[j-1]? len[i-1][j-1] :min( len[i][j-1]+1, len[i-1][j]+1 );
最长公共连续子串:
len[0][i]=0,len[j][0]=0;
i=1 to n: j=1 to m:
len[i][j]=a[i-1]==b[j-1]? len[i-1][j-1]+1: 0;
最长递增公共子序列:? 最长递增连续子序列(线性扫描即可)? 最长递增公共连续子串?
另外最长递增子序列有新的写法:
http://www.cnblogs.com/xwdreamer/archive/2011/06/21/2296995.html
O(n^2)的写法,好处是可以方便地用lst记录第一条最大长度递增序列:
len[i]=max (1, len[j]+1 if a[i]>=a[j]) j=0 to i-1. len[i]记录以i为最后一个元素的最长递增序列长度, 也可以顺便记录i的前一个点j,用以打印第一条完整子序列。甚至是所有最长子序列。 即方便记录path。
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
#include <map>
#include <stack>
// O(n^n) 方法获取
int dp(vector<int> &num){
int n=num.size();
vector<int> len(n, 1);
vector<int> lst(n, -1);
for(int i=1; i<n; i++){
for(int j=0; j<i; j++){
if(num[i]>=num[j]){
// j may be the first pre-node of i in a max-length subseq
if(len[j]+1>len[i])
// record path
len[i]=len[j]+1, lst[i]=j;
}
}
}
stack<int> path;
// get the first subseq that has the max length
int mL=-1, mI=-1;
for(int i=0; i<n; i++) if(len[i]>mL) mL=len[i], mI=i;
// get the pre-node of i
int i=mI;
while(i>=0){
path.push(i), i=lst[i];
}
// print path
while(!path.empty()){
cout<<num[path.top()]<<"->";path.pop();
}cout<<endl;
return mL;
}
int main(){
vector<int>t={9,7,5,3,4,6,8,10,-1,2};
cout<<dp(t)<<endl;
return 0;
}
最短编辑距离: 增删改
#include <iostream>
#include <algorithm>
using namespace std;
#include <vector>
#include <map>
#include <stack>
int dp(vector<int> &a, vector<int> &b){
int n=a.size(), m=b.size();
vector<vector<int> > len(n+1, vector<int>(m+1, 0));
// add
for(int i=0; i<=m; i++) len[0][i]=i;
// del
for(int i=0; i<=n; i++) len[i][0]=i;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
// change
if(a[i-1]==b[j-1]) len[i][j]=len[i-1][j-1];
else{
// add or del
len[i][j]=min(len[i-1][j]+1, len[i][j-1]+1);
}
}
}
return len[n][m];
}
int main(){
vector<int> a={1,2,3,4,5}, b={6,7,8,2,2};
cout<<dp(a,b)<<endl;
a={1,2,3,4,5}, b={};
cout<<dp(a,b)<<endl;
a={}, b={};
cout<<dp(a,b)<<endl;
return 0;
}
max递增序列枚举新的写法:
#include <iostream>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;
typedef pair<int, vector<vector<int> > > Pair;
void dp(int num[], int n){
vector< list < Pair > > a;
vector< int > minN;
for( int i=0; i<n; i++ ){
int x = num[i];
vector<int>::iterator it = upper_bound( minN.begin(), minN.end(), x );
int idx = it == minN.end()? minN.size()-1 : it - minN.begin() - 1;
if( it == minN.end() ){
minN.push_back( x );
a.push_back( list<Pair>() );
}
else
*it = x;
if ( idx < 0 ){
a[ 0 ].insert( a[0].begin(),
Pair( x, vector<vector<int> >(1, vector<int>(1, x))));
}
else {
Pair tmp( x, vector<vector<int> > () );
list< Pair >::iterator it = a[idx].begin(), j = it;
while ( it!= a[idx].end() && it->first <= x ){
tmp.second.insert( tmp.second.end(), it->second.begin(), it->second.end() );
it ++;
}
for(int i=0; i<tmp.second.size(); i++) tmp.second[i].push_back(x);
it = a[idx].begin();
while ( it!= a[idx].end() && it->first < x ) it++;
a[idx].erase( it, a[idx].end() );
a[idx+1].insert( a[idx+1].begin(), tmp );
}
}
int len=a.size();
if( len == 0 ) return;
for( list<Pair>::iterator it=a[len-1].begin(); it!=a[len-1].end(); it++ ){
vector<vector<int> > &tmp=it->second;
for(int j=0; j<tmp.size(); j++){
for( int k=0; k<tmp[j].size(); k++ ){
cout<<tmp[j][k]<<" ";
}
cout<<endl;
}
}
}
int main(){
int num[15]={1,3,2,2,4,7,2,2,2,2,6};
dp(num, 11);
return 0;
}