题目描述
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;
}
原文地址:https://www.cnblogs.com/gmh77/p/12208133.html