牛客编程巅峰赛S1第9场 - 王者 C 牛牛摆木棒
好久没写过blog了...
题意:求n的排列中第k个波浪形的排列
牛客巅峰赛系列里面少有的,还算有一点意思的题目(没错我就是在喷),可惜考场上时间不太够,想出来没码完(好吧确实是因为我一开始把找第k个的部分写麻烦了)。
首先来考虑求满足条件序列数量的问题,记$dp_{n,k,0/1}$表示长度为n,以k开头的先上升或先下降的序列数量。
$$ dp_{n,k,0} = \sum_{i=1}^{k-1} dp_{n-1,i,1} $$
$$ dp_{n,k,1} = \sum_{i=k+1}^{n} dp_{n-1,i-1,0} $$
预处理出来这个dp数组之后,按照跟dp相同的思路逐位确定最终答案即可。
#define ll long long class Solution { public: /** * * @param n int整型 木棒的个数 * @param k long长整型 第k个排列 * @return int整型vector */ ll dp[30][30][2]; vector<int> ask(int n, int now, ll k, int flag){ vector<int> res, _res; if (n>1){ if (flag == 0){ for (int j = 1; j < now; j++){ long long tmp = dp[n-1][j][1]; if (k > tmp) k-=tmp;else{ res = ask(n-1, j, k, 1); break; } } }else{ for (int j = now+1; j <= n; j++){ long long tmp = dp[n-1][j-1][0]; if (k > tmp) k-=tmp;else{ res = ask(n-1, j-1, k, 0); break; } } } } for (int i = 0; i < n-1; i++) res[i] += res[i] >= now; _res.push_back(now); for (int i = 0; i < n-1; i++) _res.push_back(res[i]); return _res; } vector<int> stick(int n, ll k) { memset(dp, 0, sizeof(dp)); dp[1][1][0] = dp[1][1][1] = 1; for (int i = 2; i <= n; i++){ for (int j = 1; j <= i; j++){ for (int k = 1; k < j; k++){ dp[i][j][0] += dp[i-1][k][1]; } for (int k = j+1; k <= i; k++){ dp[i][j][1] += dp[i-1][k-1][0]; } } } for (int a = 1; a <= n; a++){ if (dp[n][a][0] >= k){ return ask(n, a, k, 0); }else k-=dp[n][a][0]; if (dp[n][a][1] >= k){ return ask(n, a, k, 1); }else k-=dp[n][a][1]; } } };