diverta2019-2 E - Balanced Piles

diverta2019-2 E - Balanced Piles

对于一个序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n a1,a2,...,an,同时给它们分配一个 1 , 2 , . . . , n 1,2,...,n 1,2,...,n的排列 b 1 , b 2 , . . , b n b_1,b_2,..,b_n b1,b2,..,bn,满足:
如果 a i < a j ( i ≠ j ) a_i<a_j(i\neq j) ai<aj(i=j),则 b i < b j b_i<b_j bi<bj需满足。
b b b序列的性质: a i a_i ai相同的数的 b b b序列一定是连续的一段。如果 b x = 1 b_x=1 bx=1,则 a x a_x ax一定是序列中的最小值。
序列 b b b用来表示序列 a a a中数的操作顺序。
a = [ 1 , 3 , 2 , 2 , 3 , 1 ] , b = [ 2 , 6 , 3 , 4 , 5 , 1 ] a=[1,3,2,2,3,1],b=[2,6,3,4,5,1] a=[1,3,2,2,3,1],b=[2,6,3,4,5,1]先操作第 6 6 6个位置,再第 1 1 1个位置、第 3 3 3个位置、第 4 4 4个位置、第 5 5 5个位置、第 2 2 2个位置。

a 1 = a 2 = . . . = a n = 0 a_1=a_2=...=a_n=0 a1=a2=...=an=0时,有 n ! n! n!种合法的排列 b b b

随后修改一下问题:
初始有一个序列 a 1 = a 2 = . . . = a n = 0 a_1=a_2=...=a_n=0 a1=a2=...=an=0,首先需要给这个序列分配一个 1 , 2 , . . . , n 1,2,...,n 1,2,...,n的排列 b 1 , b 2 , . . . , b n b_1,b_2,...,b_n b1,b2,...,bn,然后执行下述操作若干次:
设序列中的最大值为 M M M,选择一个整数 x ∈ [ M + 1 , M + D ] x\in [M+1,M+D] x[M+1,M+D]

  1. 如果 x ≠ H x\neq H x=H,则再选择若干个数 1 ≤ i 1 < i 2 < . . . < i t ≤ n 1\le i_1<i_2<...< i_t\le n 1i1<i2<...<itn满足 b i 1 , b i 2 , . . . , b i t b_{i_1},b_{i_2},...,b_{i_t} bi1,bi2,...,bit排序后的结果是 1 , 2 , . . . , t 1,2,...,t 1,2,...,t(确定了 t t t即可确定 1 ≤ i 1 < i 2 < . . . < i t ≤ n 1\le i_1<i_2<...< i_t\le n 1i1<i2<...<itn),随后令 a i 1 = a i 2 = . . . = a i t = x a_{i_1}=a_{i_2}=...=a_{i_t}=x ai1=ai2=...=ait=x,对于 j ∉ { i 1 , i 2 , . . . , i t } j\notin \{i_1,i_2,...,i_t\} j/{i1,i2,...,it},令 b j = b j − t b_j=b_j-t bj=bjt,再给 b i 1 , b i 2 , . . . , b i t b_{i_1},b_{i_2},...,b_{i_t} bi1,bi2,...,bit分配一个 n − t + 1 , . . . , n − 1 , n n-t+1,...,n-1,n nt+1,...,n1,n的排列(有 t ! t! t!种可能的排列)。
  2. 如果 x = H x=H x=H,则令 a 1 = a 2 = . . . = a n = H a_1=a_2=...=a_n=H a1=a2=...=an=H b 1 = 1 , b 2 = 2 , . . . , b n = n b_1=1,b_2=2,...,b_n=n b1=1,b2=2,...,bn=n

问有多少中不同的操作方案可以得到 a = [ H , H , . . . , H ] , b = [ 1 , 2 , . . . , n ] a=[H,H,...,H],b=[1,2,...,n] a=[H,H,...,H],b=[1,2,...,n]

d p i dp_i dpi表示序列 a a a中最大值为 i i i时序列对 ( a , b ) (a,b) (a,b)的数量,有
d p 0 = n ! d p i = ∑ j = m a x ( 0 , i − D ) i − 1 d p j ( 1 ! + 2 ! + . . . + n ! ) ( 0 < i < H ) d p H = ∑ j = m a x ( 0 , H − D ) H − 1 d p j dp_0=n!\\ dp_i=\sum_{j=max(0,i-D)}^{i-1} dp_j(1!+2!+...+n!)(0<i<H)\\ dp_H=\sum_{j=max(0,H-D)}^{H-1} dp_j dp0=n!dpi=j=max(0,iD)i1dpj(1!+2!+...+n!)(0<i<H)dpH=j=max(0,HD)H1dpj

keyidea:在序列内决定好相同数的操作顺序,每次将最小值修改为 [ M , M + D ] [M,M+D] [M,M+D]中的某个数改成每次修改多个最小的数到 [ M + 1 , M + D ] [M+1,M+D] [M+1,M+D]中的某个数。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// const int mod=998244353;
const int mod=1e9+7;
#define inf 0x3f3f3f3f
// #define inf 0x3f3f3f3f3f3f3f3fll
// #define DEBUG
inline void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void ast(ll x,ll l,ll r){assert(x>=l&&x<=r);}
int main()
{
    #ifdef DEBUG
    freopen("1.in","r",stdin);
    freopen("1.out","w",stdout);
    #endif
    ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    int n,h,d;
    cin>>n>>h>>d;
    vector<int>f(n+1);
    f[0]=1;
    for(int i=1;i<=n;++i) f[i]=1ll*f[i-1]*i%mod;
    vector<int>dp(h+1);
    int sum=0;
    dp[0]=f[n];
    for(int i=1;i<=n;++i) sum=(sum+f[i])%mod;
    int s=dp[0];
    for(int i=1;i<=h;++i)
    {
        if(i<h) dp[i]=1ll*s*sum%mod;
        else dp[i]=s;
        s=(s+dp[i])%mod;
        if(i-d>=0) s=(s+mod-dp[i-d])%mod;
    }
    cout<<dp[h]<<'\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值