P7690 [CEOI2002] A decorative fence 题解

cnblogs

如果只是询问方案数,是 P2467 [SDOI2010] 地精部落 这道题,设 \(f_{i,j,1/0}\) 表示以 \(j\) 个数中从小到大的第 \(i\) 个数处于高/低位开头的方案数。
显然有

\[\begin{aligned} \begin{cases} f_{i,j,1}=\sum_{k=1}^{i-1}f_{k,j-1,0}\\ f_{i,j,0}=\sum_{k=i}^{j-1}f_{k,j-1,1} \end{cases} \end{aligned}\]

朴素的转移是 \(O(n^3)\) 的,拿前缀和优化一下可以做到 \(O(n^2)\)
处理出来这个后,我们利用倍增的思想查找每一位应该停留在哪个数字上,如果加上这个数字的方案数后,当前总方案数大于等于 \(C\),则这一位应该填这个数字。
具体来说,可以通过记录这一位处于高位还是低位,然后找出每一位后递归下一位来实现。具体看代码。

#include<bits/stdc++.h>
#define int long long
typedef long long ll;
typedef unsigned long long ull;
inline int read(){char ch=getchar();int x=0,f=1;for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+(ch^48);return x*f;}
const int N=25;
int n,f[N][N][N],C,ans[N];
inline void work(int x,int now,int sum,int pd){
	ans[n-sum]=x;
	if(!sum)return;
	if(pd==-1||pd==1){
		for(int i=1;i<x;++i){
			if(now+f[i][sum][0]>=C){
				work(i,now,sum-1,0);
				return;
			}
			now+=f[i][sum][0];
		}
	}
	if(pd==-1||pd==0){
		for(int i=x;i<=sum;++i){
			if(now+f[i][sum][1]>=C){
				work(i,now,sum-1,1);
				return;
			}
			now+=f[i][sum][1];
		}
	}
    \\ 递归查找,pd=1表示当前处于高位找低位,pd=0反之,pd=-1表示当前是开头,找高低位无所谓。
}
signed main(){
	// freopen("in.in","r",stdin);freopen("out.out","w",stdout);
	std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
	f[1][1][0]=1;f[1][1][1]=1;
	for(int j=2;j<=20;++j){
		for(int i=1;i<=j;++i){
			for(int k=1;k<i;++k){
				f[i][j][1]+=f[k][j-1][0];
			}
			for(int k=i;k<=j-1;++k){
				f[i][j][0]+=f[k][j-1][1];
			}
		}
	}
	int T=read();
	while(T--){
		memset(ans,0,sizeof(ans));
		n=read(),C=read();
		int st=0,zc=0;
		for(int i=1;i<=n;++i){
			zc+=f[i][n][0]+f[i][n][1];
			if(zc>=C){st=i;zc-=f[i][n][0]+f[i][n][1];break;}
		}
		work(st,zc,n-1,-1);
		std::vector<int> v;
		for(int i=1;i<=n;++i)v.push_back(i);
		v.erase(v.begin()+st-1);
		for(int i=2;i<=n;++i){
			int zc=ans[i];
			ans[i]=v[ans[i]-1];
			v.erase(v.begin()+zc-1);
		}
		for(int i=1;i<=n;++i)std::cout<<ans[i]<<' ';std::cout<<'\n';
	}
}
posted @ 2024-06-10 11:42  Ishar-zdl  阅读(11)  评论(0编辑  收藏  举报