【动态规划】51nod1780 完美序列

巧妙的转化;f前两维大小开反TLE了一发……

如果一个序列的相邻两项差的绝对值小于等于1,那么我们说这个序列是完美的。
给出一个有序数列A,求有多少种完美序列排序后和数列A相同。

Input

第一行一个数n(<=30000)表示完美序列的长度
第二行n个数,表示数列A(每个数<=10^9,每个数出现次数<=100)

Output

仅包含一个整数,表示可能的方案总数(对1,000,000,007取模)

题目分析

暑假讲过的题,今天第一眼还以为是什么玄妙计数……

因为从左到右构造不现实,于是考虑将数字从小到大构造。这样的好处在于现在插入的$i$只和上一次$i-1$的状态有关系。

$f[i][j][0/1][0/1]$表示处理到第$i$个数,第$i-1$个数两两间存空$j$个,左右两边分别是否有第$i-1$个数。转移的话就是用组合数统计,记得要预处理组合数。

所以总时间复杂度$O(n*4*100)$.

 1 #include<bits/stdc++.h>
 2 const int MO = 1000000007;
 3 const int maxn = 30035;
 4 
 5 int f[maxn][103][3][3];
 6 int fac[103],C[103][103];
 7 int n,m,ans,a[maxn],t[maxn];
 8 
 9 int read()
10 {
11     char ch = getchar();
12     int num = 0;
13     for (; !isdigit(ch); ch=getchar());
14     for (; isdigit(ch); ch=getchar())
15         num = (num<<1)+(num<<3)+ch-48;
16     return num;
17 }
18 int qmi(int a, int b)
19 {
20     int ret = 1;
21     while (b)
22     {
23         if (b&1) ret = 1ll*ret*a%MO;
24         a = 1ll*a*a%MO, b >>= 1;
25     }
26     return ret;
27 }
28 inline void Add(int &x, int y){x = (x+1ll*y)%MO;}
29 int main()
30 {
31     n = read(), fac[0] = 1;
32     for (int i=1; i<=n; i++) a[i] = read();
33     for (int i=1; i<=100; i++) fac[i] = 1ll*fac[i-1]*i%MO;
34     for (int i=0; i<=100; i++)
35         for (int j=0; j<=i; j++)
36             C[i][j] = 1ll*fac[i]*qmi(1ll*fac[j]*fac[i-j]%MO, MO-2)%MO;
37     for (int i=1, j=1; i<=n; i++)
38     {
39         while (j<=n&&a[i]==a[j+1]) j++;
40         if (a[i]+1 < a[j+1]){
41             puts("0");
42             return 0;
43         }
44         t[++m] = j-i+1, i = j;
45     }
46     f[1][t[1]-1][1][1] = 1;
47     for (int i=1; i<m; i++)
48         for (int j=0; j<t[i]; j++)
49             for (int s1=0; s1<=1; s1++)
50             for (int s2=0; s2<=1; s2++)
51                 if (f[i][j][s1][s2])
52                      for (int k=0; k<=j; k++)
53                          for (int l1=0; l1<=s1; l1++)
54                          for (int l2=0; l2<=s2; l2++)
55                              if (k+l1+l2&&t[i+1] >= k+l1+l2)
56                                 Add(f[i+1][t[i+1]-k-l1-l2][l1][l2], 1ll*f[i][j][s1][s2]*C[j][k]%MO*C[t[i+1]-1][k+l1+l2-1]%MO);
57     for (int i=0; i<=100; i++)
58         for (int j=0; j<=1; j++)
59             for (int k=0; k<=1; k++)
60                 Add(ans, f[m][i][j][k]);
61     printf("%d
",ans);
62     return 0;
63 }

END

原文地址:https://www.cnblogs.com/antiquality/p/9822939.html