【XSY2668】排列统计 DP

题目描述

  给你一个长度为 n 的排列a,每次要选择两个数,交换这两个数(这两个数可以相同)。总共要交换 k 次。

  最后要统计数列中有多少位置i满足 maxjiai=ai 。求前面这个东西的期望。

   n100,k80

题解

  毒瘤题。。。

  我们枚举每个数 y 每在个位置x的贡献。把其他数中大于 y 的看成1,把其他数中小于 y 的看成0,然后DP。

  设 fi,j,k 为交换了 i 次,1~ x1 j 1,( k 在下面解释)的方案数

  两条竖线中间是位置x

   k=0 |y|

   k=1 y|0|

   k=2 y|1|

   k=3 |0|y

   k=4 |1|y

  转移很多很繁琐,大家自己去推吧。。。

  时间复杂度:总共有 O(n2) 次DP,每次 O(nk) ,总的时间复杂度是 O(n3k)

代码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<ctime>
#include<cstdlib>
#include<utility>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
void open(const char *s)
{
#ifndef ONLINE_JUDGE
    char str[100];
    sprintf(str,"%s.in",s);
    freopen(str,"r",stdin);
    sprintf(str,"%s.out",s);
    freopen(str,"w",stdout);
#endif
}
const ll p=1000000007;
ll fp(ll a,ll b)
{
    ll s=1;
    for(;b;b>>=1,a=a*a%p)
        if(b&1)
            s=s*a%p;
    return s;
}
int x,y,i,j,k;
int n,m;
int a[100010];
ll f[90][110][5];
void add(ll &a,ll b)
{
    a=(a+b)%p;
}
ll qian0(){return (k==1||k==2)?x-2-j:x-1-j;}
ll qian1(){return j;}
ll hou0(){return (k==2?y+j-x+1:(k==3?y+j-x-1:y+j-x));}
ll hou1(){return (k==2||k==4)?n-y-j-1:n-y-j;}
ll qian0(int k){return (k==1||k==2)?x-2-j:x-1-j;}
ll qian1(int k){return j;}
ll hou0(int k){return (k==2?y+j-x+1:(k==3?y+j-x-1:y+j-x));}
ll hou1(int k){return (k==2||k==4)?n-y-j-1:n-y-j;}
int now(){return (k==1||k==3)?0:((k==2||k==4)?1:-1);}
int where(){return (k==1||k==2)?0:1;}
ll sqr(ll x){return x*x%p;}
ll gao()
{
    memset(f,0,sizeof f);
    int h=0,hh;
    for(i=1;i<x;i++)
        if(a[i]>y)
            h++;
    for(i=1;i<=n;i++)
        if(a[i]==y)
        {
            hh=i;
            break;
        }
    if(hh==x)
        f[0][h][0]=1;
    else if(hh<x)
        if(a[x]<y)
            f[0][h][1]=1;
        else
            f[0][h][2]=1;
    else
        if(a[x]<y)
            f[0][h][3]=1;
        else
            f[0][h][4]=1;
    for(i=0;i<m;i++)
        for(j=0;j<y;j++)
        {
            for(k=0;k<=4;k++)
                if(f[i][j][k])
                {
                    add(f[i+1][j][k],f[i][j][k]*sqr(qian0()+qian1()));
                    add(f[i+1][j][k],f[i][j][k]*sqr(hou0()+hou1()));
                    add(f[i+1][j][k],f[i][j][k]*2*qian0()%p*hou0());
                    add(f[i+1][j][k],f[i][j][k]*2*qian1()%p*hou1());
                    add(f[i+1][j][k],f[i][j][k]);
                    if(j)
                        add(f[i+1][j-1][k],f[i][j][k]*2*qian1()%p*hou0());
                    if(j<y-1)
                        add(f[i+1][j+1][k],f[i][j][k]*2*qian0()%p*hou1());
                    if(k)
                        add(f[i+1][j][k],f[i][j][k]);
                }
            if(f[i][j][0])
            {
                add(f[i+1][j][1],f[i][j][0]*2*qian0(0));
                if(j)
                    add(f[i+1][j-1][2],f[i][j][0]*2%p*qian1(0));
                add(f[i+1][j][3],f[i][j][0]*2*hou0(0));
                add(f[i+1][j][4],f[i][j][0]*2*hou1(0));
            }
            if(f[i][j][1])
            {
                add(f[i+1][j][0],f[i][j][1]*2);
                add(f[i+1][j][1],f[i][j][1]*2*(qian0(1)+qian1(1)));
                add(f[i+1][j][3],f[i][j][1]*2*hou0(1));
                if(j<y-1)
                    add(f[i+1][j+1][3],f[i][j][1]*2%p*hou1(1));
                add(f[i+1][j][1],f[i][j][1]*2*(qian0(1)+hou0(1)));
                add(f[i+1][j][2],f[i][j][1]*2*hou1(1));
                if(j)
                    add(f[i+1][j-1][2],f[i][j][1]*2%p*qian1(1));
            }

            if(f[i][j][2])
            {
                if(j<y-1)
                    add(f[i+1][j+1][0],f[i][j][2]*2);
                add(f[i+1][j][2],f[i][j][2]*2*(qian0(2)+qian1(2)));
                add(f[i+1][j][4],f[i][j][2]*2*hou0(2));
                if(j<y-1)
                    add(f[i+1][j+1][4],f[i][j][2]*2%p*hou1(2));
                add(f[i+1][j][1],f[i][j][2]*2*hou0(2));
                if(j<y-1)
                    add(f[i+1][j+1][1],f[i][j][2]*2%p*qian0(2));
                add(f[i+1][j][2],f[i][j][2]*2*(qian1(2)+hou1(2)));
            }

            if(f[i][j][3])
            {
                add(f[i+1][j][0],f[i][j][3]*2);
                add(f[i+1][j][3],f[i][j][3]*2*(hou0(3)+hou1(3)));
                add(f[i+1][j][1],f[i][j][3]*2*qian0(3));
                if(j)
                    add(f[i+1][j-1][1],f[i][j][3]*2*qian1(3));
                add(f[i+1][j][3],f[i][j][3]*2*(qian0(3)+hou0(3)));
                add(f[i+1][j][4],f[i][j][3]*2*hou1(3));
                if(j)
                    add(f[i+1][j-1][4],f[i][j][3]*2*qian1(3));
            }

            if(f[i][j][4])
            {
                add(f[i+1][j][0],f[i][j][4]*2);
                add(f[i+1][j][4],f[i][j][4]*2*(hou0(4)+hou1(4)));
                add(f[i+1][j][2],f[i][j][4]*2*qian0(4));
                if(j)
                    add(f[i+1][j-1][2],f[i][j][4]*2*qian1(4));
                add(f[i+1][j][3],f[i][j][4]*2*hou0(4));
                if(j<y-1)
                    add(f[i+1][j+1][3],f[i][j][4]*2*qian0(4));
                add(f[i+1][j][4],f[i][j][4]*2*(qian1(4)+hou1(4)));
            }
        }
    return f[m][0][0];
}
int main()
{
    open("pltj");
    scanf("%d%d",&n,&m);
    int i;
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    ll ans=0;
    for(x=1;x<=n;x++)
        for(y=1;y<=n;y++)
            if(y>=x)
                ans=(ans+gao())%p;
    ans=ans*fp(fp(n,2*m),p-2)%p;
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值