[hdu5225][BC#40]Tom and permutation

  好久没写题解了。。GDKOI被数位DP教做人了一发,现在终于来填数位DP的大坑了>_<。

  发现自己以前写的关于数位DP的东西...因为没结合图形+语文水平拙计现在已经完全看不懂了嗯。

  看来看去感觉还是这篇关于数位DP的介绍靠谱:http://wenku.baidu.com/view/d2414ffe04a1b0717fd5dda8.html

  想题的时候结合图形食用效果更佳。

 

  题意是说,对于一个给定的n的排列,要求出 (所有字典序<给定排列的排列)的逆序对个数和。

  预处理出f[i]表示i的所有排列中,逆序对的个数。(事实上也是i个数的所有排列中逆序对的个数)

  然后像那篇论文里面的姿势处理就好了。

  每次把逆序对分为三种:已确定的数和后面的数之间的逆序对、已确定的数之间的逆序对,后面的数之间的逆序对。

  前两种可以放到一起统计(和后面的数的具体顺序无关),第三种就是预处理出来的东西。

 

  顺便在hdu上压了发代码最短= =(空间实在无力>_<

 1 #include<cstdio>
 2 #include<cstring>
 3 #define ll long long
 4 using namespace std;
 5 const ll modd=1000000007;
 6 ll f[101],a[101];//a数组存阶乘的值
 7 ll i,j;
 8 int n,x;
 9 bool u[101];
10 inline ll run(){
11     ll ans=0,now=0,mn;
12     memset(u,0,n+1);
13     for(i=1;i<=n;i++){
14         scanf("%d",&x);u[x]=1;
15         for(j=1,mn=0;j<x;j++)
16             if(!u[j])ans+=f[n-i]+a[n-i]*(now+mn),ans%=modd,mn++;
17         for(j=1;j<x;j++)if(!u[j])now++;
18     }
19     return ans;
20 }
21 int main(){
22     a[1]=1;f[1]=0;
23     for(i=2;i<=100;i++){
24         a[i]=a[i-1]*i%modd;
25         f[i]=(i*f[i-1]+a[i-1]*(i-1)*i/2)%modd;
26     }
27     while(scanf("%d",&n)==1)printf("%lld\n",run());
28     return 0;
29 }
View Code

 

posted @ 2016-02-24 22:03  czllgzmzl  阅读(236)  评论(0编辑  收藏  举报