[关闭]
@ysner 2018-05-26T00:30:47.000000Z 字数 1623 阅读 1863

交换

图论


题面

给定一个的排列。一个的排列被认为是优美的排列,当且仅当满足下列条件:
对排列进行次交换。

解析

这题构造数据挺难的,据说必须恰好有个逆序对。
还是举个栗子通俗易懂。
比如,有一数列,现在我们要把它转化为
怎么转呢?
虽然我们不能马上说出其操作整体顺序,但我们可以说出部分操作间的顺序。
我们肯定要把挪到,则有先后顺序;同时,前。
我们肯定要把挪倒,则有先后顺序;同时,前。
我们肯定要把挪倒,则有先后顺序
那个“同时”的附加条件保证的是先后顺序走了一边后,不会把已挪完的数再挪位置。
得到如此多的二元关系,我们就可以建图,前面的连一条边向后面的。
问题转化为“一笔画”该图的方案数。

  1. #include<iostream>
  2. #include<cstdlib>
  3. #include<cstdio>
  4. #include<algorithm>
  5. #include<cstring>
  6. #include<cmath>
  7. #include<queue>
  8. #include<map>
  9. const int N=52;
  10. const int mod=1e9+7;
  11. il ll read(){
  12. RG ll d=0,w=1;char ch=getchar();
  13. while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
  14. if(ch=='-')w=-1,ch=getchar();
  15. while(ch<='9'&&ch>='0')d=d*10+ch-48,ch=getchar();
  16. return d*w;
  17. }
  18. int n,p[N],s[N],ans,f[N][N];
  19. bool a[N][3];
  20. il void end(){puts("0");exit(0);}
  21. il void add(int i,int j){
  22. if(i==n||j==n)return;
  23. if(i<j){if(a[j][2])end();a[j][1]=1;}
  24. else{if(a[i][1])end();a[i][2]=1;}
  25. }
  26. int main()
  27. {
  28. file();
  29. n=read();
  30. for(RG int i=1;i<=n;i++)p[i]=read()+1;
  31. for(RG int i=1;i<=n;i++)
  32. {
  33. if(p[i]>i){
  34. for(RG int j=i;j<p[i]-1;j++)add(j,j+1);
  35. add(p[i],p[i]-1);
  36. }
  37. else if(p[i]<i){
  38. for(RG int j=i-1;j>p[i];j--)add(j,j-1);
  39. add(p[i]-1,p[i]);
  40. }
  41. else if(p[i]==i)end();
  42. }
  43. f[1][1]=1;
  44. for(RG int i=2;i<=n-1;i++)
  45. {
  46. RG int sum=0;
  47. if(!a[i][1]&&!a[i][2])
  48. {
  49. for(RG int j=1;j<i;j++)(sum+=f[i-1][j])%=mod;
  50. for(RG int j=1;j<=i;j++)f[i][j]=sum;
  51. }
  52. else if(a[i][2]){
  53. for(RG int j=i-1;j>=1;j--){
  54. (sum+=f[i-1][j])%=mod;f[i][j]=sum;
  55. }
  56. }
  57. else if(a[i][1]){
  58. for(RG int j=1;j<i;j++){
  59. (sum+=f[i-1][j])%=mod;
  60. f[i][j+1]=sum;
  61. }
  62. }
  63. }
  64. for(RG int i=1;i<=n-1;i++)(ans+=f[n-1][i])%=mod;
  65. printf("%d\n",ans);return 0;
  66. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注