这道题卡读题卡得很死......首先他告诉我们读循环的时候要顺着圈读,然后又说这个圈在数列上要以最大数开始读,而且以这样的循环的首数排序,得到的序列与原序列一样那么他就是可行序列,所以我们发现任何一个可行序列他的循环一定是连续的一块,因为假设我们有一个循环 x->y->z->a->x,并且假设x最大,那么在数列上只会出现x,y,z,a,那么我们根据循环的定义,他们的原本位置也在这几个里面那么也就是各个循环是一块一块的,然后我们在看刚才的假设,我们发现z是最大的!!!然后发现当且仅当一个循环里是两个数他才是合法的,然后我们归纳一下,一个可行排列里的循环只能是两个相邻的数交换位置,然后我们把这个数列往后排发现是Fibonacci数列,然后就循环一波就好了。
这道题当然如果你是在是没推出来的话也可以用看脸的打表找规律,但是我还真觉得如果看懂题的话不如推..
#include <cstdio> typedef long long LL; namespace Fib{ LL f[100]; inline void get(){ f[0]=f[1]=f[2]=1; for(int i=3;i<=50;i++) f[i]=f[i-1]+f[i-2]; } } namespace Main{ int n; LL k; int Ans[55]; inline void get(){ scanf("%d%lld",&n,&k); int pos=1; while(pos<=n){ LL temp=0; int now=0; for(int i=0;i<n;i++){ temp+=Fib::f[i]; if(temp>=k){ now=i; break; } } if(temp==k){ if(now==0){ for(int i=pos;i<=n;i++){ Ans[i]=i; } break; } for(int i=pos;i<=n-now-1;i++) Ans[i]=i; for(int i=n-now;i+1<=n;i+=2) Ans[i+1]=i,Ans[i]=i+1; if(Ans[n]==0)Ans[n]=n; break; } k-=temp-Fib::f[now]; for(int i=pos;i<=n-now-1;i++) Ans[i]=i; Ans[n-now]=n-now+1; Ans[n-now+1]=n-now; pos=n-now+2; } } } int main(){ Fib::get(); Main::get(); for(int i=1;i<=Main::n;i++) printf("%d ",Main::Ans[i]); return 0; }