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; }