• [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
    ",run());
    28     return 0;
    29 }
    View Code
  • 相关阅读:
    集训笔记——dp继续
    集训笔记——各种dp(dp杂谈)
    集训笔记——dp
    洛谷P3197 [HNOI2008]越狱 题解
    集训笔记——杂题选讲(图论,dp)
    集训笔记——杂题选讲(带数学推导的递推、递归和dp,卡特兰数)
    滑动窗口+二分--P3957 跳房子
    差分+二分答案--P1083 借教室
    逆序对--P1966 火柴排队
    数位dp--P2657 [SCOI2009] windy 数
  • 原文地址:https://www.cnblogs.com/czllgzmzl/p/5215320.html
Copyright © 2020-2023  润新知