1. 程式人生 > >5、不等式數列--百度2017春招

5、不等式數列--百度2017春招

同類項 需要 clas dex -s 數量 tmp 表示 所有

[編程題] 不等式數列 時間限制:1秒 空間限制:32768K 度度熊最近對全排列特別感興趣,對於1到n的一個排列,度度熊發現可以在中間根據大小關系插入合適的大於和小於符號(即 ‘>‘ 和 ‘<‘ )使其成為一個合法的不等式數列。但是現在度度熊手中只有k個小於符號即(‘<‘‘)和n-k-1個大於符號(即‘>‘),度度熊想知道對於1至n任意的排列中有多少個排列可以使用這些符號使其為合法的不等式數列。 輸入描述: 輸入包括一行,包含兩個整數n和k(k < n ≤ 1000) 輸出描述: 輸出滿足條件的排列數,答案對2017取模。 輸入例子: 5 2 輸出例子:
66 解題思路:首先想到的是暴力的方式解決該問題 1)求出所有1-n的數的全排列分別存入vector中 2)對每一種排列,如果前一個小於後一個,小於數目--;如果大於則,大於數目-- 3)如果一次操作過後,xiaoyu為0 && dayu為0 則符合條件,result++ 4)輸出result%2017
 1 #include <iostream>
 2 #include <vector>
 3 using namespace std;
 4 
 5 
 6 void swap(int* p1,int* p2)
 7 {
 8     int temp = *p1;
9 *p1 = *p2; 10 *p2 = temp; 11 } 12 vector<vector<int> > res; 13 //獲得1-n 全排列的個數,並存儲全排列結果 14 void recall(int* arr,int len,int index,int *count) 15 { 16 vector<int> tmp; 17 if (index<=0) 18 { 19 (*count)++;//由於優先級的關系,記得加括號 20 for(int i=0;i<len;i++)
21 { 22 //cout<<arr[i]<<" "; 23 tmp.push_back(arr[i]); 24 } 25 res.push_back(tmp); 26 tmp.clear(); 27 //cout<<endl; 28 return; 29 } 30 for (int i=index;i>=0;i--) 31 { 32 swap(&arr[index],&arr[i]); 33 recall(arr,len,index-1,count); 34 swap(&arr[index],&arr[i]); 35 } 36 } 37 38 39 int main() 40 { 41 int n; 42 int k; 43 while(cin>>n>>k) 44 { 45 int count = 0; 46 int result = 0; 47 int a[n]; 48 49 for(int i=0;i<n;i++) 50 { 51 a[i] = i+1; 52 } 53 recall(a,n,n-1,&count); 54 //cout<<count<<endl; 55 for(int i=0;i<count;i++) 56 { 57 int xiaoyu = k; 58 int dayu = n - k - 1; 59 for(int j=0;j<n-1;j++) 60 { 61 //cout<<res[i][j]<<" "; 62 if(res[i][j]< res[i][j+1]) 63 { 64 xiaoyu--; 65 } 66 else if(res[i][j]>res[i][j+1]) 67 { 68 dayu--; 69 } 70 } 71 //cout<<endl; 72 //cout<<"k"<<xiaoyu<<"add"<<dayu<<endl; 73 if(xiaoyu==0 && dayu == 0) 74 { 75 result++; 76 } 77 } 78 cout<<result%2017<<endl; 79 } 80 return 0; 81 }

技術分享

正確解法: 遞歸公式:dp[i][j] = (dp[i - 1][j - 1] * (i - j) + dp[i - 1][j] * (j + 1)) % 2017; dp[i][j]表示有i個數字及j個小於號所能組成的數量(大於號數量當然是i - j - 1次,後面需要使用) 而加入第i + 1個數字時,分以下四種情況: 1、如果將i+1插入當前序列的開頭,即有了1<2,加入後成為3>1<2,會發現等於同時加入了一個大於號 2、如果將i+1插入當前序列末尾,即1<2變成了 1<2<3,會發現等於同時加入了一個小於號 3、如果將i+1加入一個小於號之間,即已經有 1<2了,向中間加入3,會發現變成了1<3>2,等於同時加入了一個大於號 4、如果將i+1加入一個大於號中間,即有了2>1,變成了2<3>1,等於同時加入了一個小於號 綜上所述,dp[i][j]等於以上四種情況之和: dp[i - 1][j] //將i加在開頭等於加入一個大於號,即要求i-1個數時已經有了j個小於號 dp[i - 1][j - 1] //將i加在末尾等於加入一個小於號,即要求i-1個數時已經有了j-1個小於號 dp[i - 1][j] * j //將i加在任意一個小於號之間,等於加入了一個大於號;即要求i-1個數時已經有了j個小於號,每個小於號都可以進行這樣的一次插入 dp[i - 1][j - 1] * (i- j - 1) //將i加在任意一個大於號之間,等於加入了一個小於號;即要求i-1個數時有了j-1個小於號,而此時共有(i - 1) - (j - 1)- 1個大於號,每個大於號都要進行一次這樣的操作 合並同類項即為 dp[i][j] = (dp[i - 1][j - 1] * (i - j) + dp[i - 1][j] * (j + 1)) 最後要記得取模。。。 初始化dp[i][0] = 1 因為全部為大於號時,只有一種排列方式
 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 int main()
 6 {
 7     int dp[1005][1005];
 8     int n, k;
 9     while(cin>>n>>k)
10     {
11         for(int i = 1; i <= n; i++)
12         {
13             dp[i][0] = 1;
14         }
15         for(int i = 2; i <= n; i++)
16         {
17             for(int j = 1; j <= k; j++)
18             {
19                 dp[i][j] = (dp[i - 1][j - 1] * (i - j) + dp[i - 1][j] * (j + 1)) % 2017;
20             }
21         }
22         cout << dp[n][k] % 2017 << endl;
23     }
24     return 0;
25 }

技術分享

5、不等式數列--百度2017春招