今天状态不佳。眼看大佬纷纷退役,顿时觉得希望全无。
先dp出i个数,j个逆序对的方案数,然后一位位枚举就可以了。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> using namespace std; #define rep(i,j,k) for(i=j;i<=k;++i) #define per(i,j,k) for(i=j;i>=k;--i) #define ll long long #define db double #define mkp(x,y) make_pair(x,y) #define pll pair<ll,ll> #define X first #define Y second const ll N=301,inf=10000000000001LL; ll k,f[N][50000];int n,x,rg;bool b[N]; void g(int i,int j){ int h;f[i][j]=inf; rep(h,0,j)f[i][rg--]=f[i][h]; while(rg>j)f[i][rg--]=inf; } int main(){ int h,i,j,cnt; scanf("%d%lld%d",&n,&k,&x); rep(i,1,n){ f[i][0]=1;rg=i*(i-1)>>1; rep(j,1,i-1){ f[i][j]=f[i][j-1]+f[i-1][j]; if(f[i][j]>inf){ g(i,j);break;} } rep(j,i,rg){ f[i][j]=f[i][j-1]-f[i-1][j-i]+f[i-1][j]; if(f[i][j]>inf){ g(i,j);break;} } } per(h,n-1,1){ rep(i,1,n)if(!b[i]){ cnt=0; per(j,i-1,1)cnt+=!b[j]; if(f[h][x-cnt]<k)k-=f[h][x-cnt]; else break; } b[i]=1;x-=cnt;printf("%d ",i); } rep(i,1,n)if(!b[i]){ printf("%d\n",i);return 0; } }