6439. GDOI2020模拟01.17小 ω 数排列

Posted gmh77

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了6439. GDOI2020模拟01.17小 ω 数排列相关的知识,希望对你有一定的参考价值。

题目描述

Description
技术图片

Input
技术图片

Output
技术图片

Sample Input
Sample Input1
4 10
3 6 2 9

Sample Input2
8 35
3 7 1 5 10 2 11 6

Sample Output
Sample Output1
6

【样例 1 解释】
共有 6 个排列符合条件,它们是 (1, 3, 2, 4),(2, 4, 1, 3),(3, 1, 2, 4),(3, 1, 4, 2),(4, 2, 1, 3),(4, 2, 3, 1)。

Sample Output2
31384

Data Constraint
技术图片

题解

原题:LOJ#2743. 「JOI Open 2016」摩天大楼

吼题

显然题目所计算的是一个折线的总长

由于不好从左往右放,所以考虑从下往上放(ai从小到大)

(f[i][j][k][l=0/1/2])表示放了(a[1sim i]),形成了(j)段,折线在(y=ai)这条线下的长度之和为(k),有(l)段和边界相连

那么当前段的边界个数即为(2j-l),也就是说从(a[i])推到(a[i+1])(k)会增加((a[i+1]-a[i])*(2j-l))

分类讨论新加的(a[i+1])会放到哪里,那么有五种情况:

①新开一段:(j+1),方案数(j+1-l)

②把某两段相连:(j-1),方案数(j-1)

③和某一段相连:(j)不变,方案数(2j-l)

④和头/尾相连:(j+1,l+1),方案数(2-l)

⑤把头/尾和最靠近的一段相连:(j)不变,(l+1),方案数(2-l)

最后答案为(sum{f[n][1][0sim L][2]})

code

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define add(a,b) a=((a)+(b))%1000000007
#define mod 1000000007
#define file
using namespace std;

int a[1001];
long long f[101][101][1001][3];
int n,L,i,j,k,l,s;
long long ans;

int main()
{
    freopen("count.in","r",stdin);
    #ifdef file
    freopen("count.out","w",stdout);
    #endif
    
    scanf("%d%d",&n,&L);
    fo(i,1,n)
    scanf("%d",&a[i]);
    
    if (n==1)
    {
        printf("1
");
        return 0;
    }
    
    sort(a+1,a+n+1);
    
    f[1][1][0][0]=1;
    f[1][1][0][1]=2;
    
    fo(i,1,n-1)
    {
        fo(j,1,n)
        {
            fo(k,0,L)
            {
                fo(l,0,2)
                if (f[i][j][k][l] && k+(2*j-l)*(a[i+1]-a[i])<=L)
                {
                    s=k+(2*j-l)*(a[i+1]-a[i]);
                    
                    add(f[i+1][j+1][s][l],f[i][j][k][l]*(j+1-l));
                    add(f[i+1][j-1][s][l],f[i][j][k][l]*(j-1));
                    add(f[i+1][j][s][l],f[i][j][k][l]*(2*j-l));
                    if (l<2)
                    {
                        add(f[i+1][j+1][s][l+1],f[i][j][k][l]*(2-l));
                        add(f[i+1][j][s][l+1],f[i][j][k][l]*(2-l));
                    }
                }
            }
        }
    }
    
    fo(k,0,L)
    add(ans,f[n][1][k][2]);
    
    printf("%lld
",ans);
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}

以上是关于6439. GDOI2020模拟01.17小 ω 数排列的主要内容,如果未能解决你的问题,请参考以下文章

6441. GDOI2020模拟01.17小 ω 维护序列

6441. GDOI2020模拟01.17小 ω 维护序列

6445. GDOI2020模拟01.19String

6438. GDOI2020模拟01.16树上的鼠(长链剖分)

6442. GDOI2020模拟01.18钩子

6464. GDOI2020模拟02.07矩阵