hdu3043Number game(dp+dfs)
题意:给你所有1-n的波浪型排列,输出按字典序将这些序列排序后第k小的数列。
思路:可以先预处理出第i个位置是j的上波浪方案数和下波浪方案数。对于每一位,从小到大枚举j,如果当前的总方案数刚好大于等于k,那么答案数列中这个位置一定是j,如此dfs找下去。
因为输入数据有很多的t,一直WA在这个地方,测数据时也发现数据不对劲,问学长要了数据才发现这个坑。
#include<cstdio> #include<cmath> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<queue> #include<functional> using namespace std; const int N=25; unsigned long long m,fu[N][N],fd[N][N]; int i,j,k,t,n; int a[N]; void dfs(int d,long long k,int pre,int tp) { if (d==0) return ; long long sum=0; int i; if (tp==-1) { for (i=1;i<pre;i++) { if (sum+fu[d][i]>=k) break; sum+=fu[d][i]; } } else { for (i=pre;i<=d;i++) { if (sum+fd[d][i]>=k) break; sum+=fd[d][i]; } } a[d]=i; dfs(d-1,k-sum,i,-tp); } int main() { fd[1][1]=fu[1][1]=1; for (i=2;i<=20;i++) { for (j=1;j<=i;j++) { for (k=j;k<=i-1;k++) fu[i][j]+=fd[i-1][k]; for (k=1;k<=j-1;k++) fd[i][j]+=fu[i-1][k]; } } while(~scanf("%d",&t)) while(t--) { scanf("%d%lld",&n,&m); if (n>250) n/=0; long long sum=0; for (i=1;i<=n;i++) { if (sum+fd[n][i]>=m) { a[n]=i; dfs(n-1,m-sum,i,-1); break; } sum+=fd[n][i]; if (sum+fu[n][i]>=m) { a[n]=i; dfs(n-1,m-sum,i,1); break; } sum+=fu[n][i]; } for (i=2;i<=n;i++) for (j=1;j<i;j++) if (a[i]<=a[j]) a[j]++; for (i=n;i>1;i--) printf("%d ",a[i]); printf("%d\n",a[1]); } }