[SDOI2010]地精部落 题解
题目传送门
题目大意
已知一个长度为 \(n\) 的排列 \(p_1,p_2,\dots,p_n\) 满足对于任意的 \(i\in \{2,3,\dots,n-1\}\) 都有 \(p_{i-1}
题目解析
考虑 DP.
但是我们发现由于限制我们很难进行递推,所以我们设 \(f_i\) 代表选择 \(1,2,\dots,i\) 的个数,并且这些序列都必须满足第一个数字比第二个大。显然我们发现答案就是 \(f_n\times2\).
我们设第 \(i\) 个数字放在第 \(j\) 个位置.因为 \(i\) 是最大的数字,所以 \(j\) 一定是奇数. 而原来的 \(i-1\) 个数字我们可以任选 \(j\) 个放在前面,所以还要乘上 \(C_{i-1}^{j}\)。
不难得到:
这样就可以做到 \(\Theta\left(n^2\right)\) 的时间复杂度了.
当然我们发现由于 \(p\) 不是质数,所以我们不能通过逆元来求解。并且我们发现如果直接用杨辉三角预处理的话会 MLE,所以我们需要滚动数组。(计算 \(f_i\) 的时候只需要知道 \(C_{i-1}^{0},C_{i-1}^{1},\dots,C_{i-1}^{i-1}\))这个时候空间复杂度就是 \(\Theta\left(n\right)\) 的。
代码:
#include
#define db double
#define pc putchar
#define U unsigned
#define ll long long
#define ld long double
#define ull unsigned long long
#define Me(a,b) memset(a,b,sizeof(a))
template _T mabs(_T a){ return a>0?a:-a; }
template _T mmax(_T a,_T b){ return a>b?a:b; }
template _T mmin(_T a,_T b){ return a void mswap(_T &a,_T &b){ _T tmp=a; a=b; b=tmp; return; }
template void print(_T x){ if(x<0) putchar('-'),x=-x;
if(x>9) print(x/10); putchar((x%10)+48); return; }
#define EPS (1e-7)
#define INF (0x7fffffff)
#define LL_INF (0x7fffffffffffffff)
#define maxn 4239
#define Type int
using namespace std;
Type read(){
char c=getchar(); Type s=0; int flag=0;
while((c<'0'||c>'9')&&c!='-') c=getchar();
if(c=='-') c=getchar(),flag=1;
while('0'<=c&&c<='9'){ s=(s<<1)+(s<<3)+(c^48); c=getchar(); }
if(flag) return -s; return s;
}
int n;
ll f[maxn],c[2][maxn],p;
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=read(); p=read(); f[0]=f[1]=1; c[0][0]=c[1][0]=c[1][1]=1; int i,j;
for(i=2;i<=n;i++){
for(j=1;j