1. 程式人生 > >【XSY2668】排列統計 DP

【XSY2668】排列統計 DP

自己 解釋 復雜度 utili gpo 每次 lin ctime h+

題目描述

  給你一個長度為\(n\)的排列\(a\),每次要選擇兩個數,交換這兩個數(這兩個數可以相同)。總共要交換\(k\)次。

  最後要統計數列中有多少位置\(i\)滿足\(\max_{j\leq i}a_i=a_i\)。求前面這個東西的期望。

  \(n\leq 100,k\leq 80\)

題解

  我們枚舉每個數\(y\)每在個位置\(x\)的貢獻。把其他數中大於\(y\)的看成\(1\),把其他數中小於\(y\)的看成\(0\),然後DP。

  設\(f_{i,j,k}\)為交換了\(i\)次,\(1\)~\(x-1\)\(j\)\(1\),(\(k\)在下面解釋)的方案數

  兩條豎線中間是位置\(x\)

  \(k=0\)\(|y|\)

  \(k=1\)\(y|0|\)

  \(k=2\)\(y|1|\)

  \(k=3\)\(|0|y\)

  \(k=4\)\(|1|y\)

  轉移很多很繁瑣,大家自己去推吧。。。

  時間復雜度:總共有\(O(n^2)\)次DP,每次\(O(nk)\),總的時間復雜度是\(O(n^3k)\)

代碼

#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; }

【XSY2668】排列統計 DP