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[1\sim 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][0\sim 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\n");
        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\n",ans);
    
    fclose(stdin);
    fclose(stdout);
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/gmh77/p/12208133.html