前置知识
解法
方案数统计同luogu P2467 [SDOI2010] 地精部落,但部分写得不太好看的状态转移方程在本题中并不适用,但仍可借鉴其“离散化”思想。
考虑试填。
设 \(f_{i,j,0/1}\) 表示用 \(i\) 块不同的木板构成栅栏,其中最左边的木板的长度从小到大排在第 \(j\) 位(仅是相对大小关系),处于低位/高位的方案数,状态转移方程为 \(\begin{cases} f_{i,j,0}=\sum\limits_{k=j}^{i-1}f_{i-1,k,1} \\ f_{i,j,1}=\sum\limits_{k=1}^{j-1}f_{i-1,k,0} \end {cases}\),边界为 \(f_{1,1,0/1}=1\)。
特别处理第 \(1\) 块木板的长度和低/高位情况 \(k\)。接着枚举每位的实际长度 \(j\) 和排名 \(rk\) 使其符合排名即可。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
ll f[25][25][2],vis[25];
int main()
{
ll t,n,c,ans,rk,i,j,k,h;
cin>>t;
f[1][1][0]=f[1][1][1]=1;
for(i=2;i<=20;i++)
{
for(j=1;j<=i;j++)
{
for(k=j;k<=i-1;k++)
{
f[i][j][0]+=f[i-1][k][1];
}
for(k=1;k<=j-1;k++)
{
f[i][j][1]+=f[i-1][k][0];
}
}
}
for(h=1;h<=t;h++)
{
cin>>n>>c;
k=ans=-1;
memset(vis,0,sizeof(vis));
for(i=1;i<=n;i++)
{
if(f[n][i][1]>=c)
{
ans=i;
k=1;
break;
}
else
{
c-=f[n][i][1];
}
if(f[n][i][0]>=c)
{
ans=i;
k=0;
break;
}
else
{
c-=f[n][i][0];
}
}
vis[ans]=1;
cout<<ans<<" ";
for(i=2;i<=n;i++)
{
k^=1;
rk=0;
for(j=1;j<=n;j++)
{
if(vis[j]==0)
{
rk++;
if((k==0&&j<ans)||(k==1&&j>ans))
{
if(f[n-i+1][rk][k]>=c)
{
ans=j;
break;
}
else
{
c-=f[n-i+1][rk][k];
}
}
}
}
vis[ans]=1;
cout<<ans<<" ";
}
cout<<endl;
}
return 0;
}
标签:decorative,25,题解,long,vis,CEOI2002,ans,define,rk
From: https://www.cnblogs.com/The-Shadow-Dragon/p/18282868