zoukankan      html  css  js  c++  java
  • 【AT2366】[AGC012F] Prefix Median(DP)

    点此看题面

    • 给定一个长度为(2n-1)的序列(a),你可以将它重新排列。
    • 定义(b_i)为前(2i-1)个数的中位数,求有多少种可能的(b)
    • (nle50)

    序列合法的充要条件

    首先,考虑(b_i)的上下界,必然是从(a)中最小的(2i-1)个数的中位数到最大的(2i-1)个数的中位数。

    然后,考虑(b_i)的变化值,发现加入两个数最多让中位数移动一位,也就是说,不能有任何之前出现过的数的值在(b_i)(b_{i+1})之间。

    这是必要条件,同时也是充分的,因为任意一个符号条件的序列我们都能构造出来。

    反向考虑

    我们从后往前考虑,那么也就是说在之后选中的数之间不能出现新的中位数。

    因此设(f_{i,j,k})表示处理完第(i)位,在取值下界到(b_i)最小值之间有(j)种取法,在(b_i)最大值到取值上界之间有(k)种取法的方案数。

    转移的时候枚举一下新选中的(b_i)即可。

    但注意处理数字重复的情况,即如果新的边界和旧边界值不同我们需要把取法(j/k)增加(1),相同则不能增加。

    代码:(O(n^4))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50
    #define X 1000000007
    #define Inc(x,y) ((x+=(y))>=X&&(x-=X))
    using namespace std;
    int n,a[N<<1],f[N+5][N<<1][N<<1];
    int main()
    {
    	RI i,j,k,p;for(scanf("%d",&n),i=1;i<=2*n-1;++i) scanf("%d",a+i);sort(a+1,a+2*n);
    	RI x,y;for(f[i=n][0][0]=1;i^1;--i) for(j=0;j<=2*n-1;++j) for(k=0;k<=2*n-1;++k) if(f[i][j][k])//从后往前
    	{
    		x=j+(a[i-1]!=a[i]),y=k+(a[2*n-i]!=a[2*n-i+1]),Inc(f[i-1][x][y],f[i][j][k]);//边界上数不同则取法加1;不变
    		for(p=0;p^x;++p) Inc(f[i-1][p][y+1],f[i][j][k]);for(p=0;p^y;++p) Inc(f[i-1][x+1][p],f[i][j][k]);//左边变化;右边变化
    	}
    	RI t=0;for(j=0;j<=2*n-1;++j) for(k=0;k<=2*n-1;++k) Inc(t,f[1][j][k]);return printf("%d
    ",t),0;//统计答案
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    BZOJ 3505: [Cqoi2014]数三角形 数学
    BZOJ 3931: [CQOI2015]网络吞吐量 最大流
    BZOJ 4236: JOIOJI MAP
    BZOJ 4247 挂饰 背包DP
    hihocoder #1224 : 赛车 dfs
    hihocoder #1223 : 不等式 水题
    BZOJ 3224: Tyvj 1728 普通平衡树 treap
    uoj #31. 【UR #2】猪猪侠再战括号序列 贪心
    BZOJ 1005: [HNOI2008]明明的烦恼 Purfer序列 大数
    心跳回忆4 攻略
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT2366.html
Copyright © 2011-2022 走看看