P5520 [yLOI2019] 青原樱
Posted may-2nd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5520 [yLOI2019] 青原樱相关的知识,希望对你有一定的参考价值。
部分分比较多,依次讲一讲。
因为带编号,所以最后答案要乘上 (m!)。
对于子任务 1,直接输出 1%p
,时间复杂度 (O(1))。
对于子任务 2,dfs 枚举每个位置是否种植,时间复杂度 (O(2^n))。
对于子任务 3,设 (f_{i,j}) 为种了 (i) 株幼苗,最后一株种在位置 (j) 的方案数。
[f_{i,j}=sum_{k<j-1}f_{i-1,k}
]
直接转移即可,时间复杂度 (O(n^2m))。
对于子任务 4,易发现子任务 3 中的 DP 可以用前缀和优化到 (O(nm))。
对于子任务 5,我们发现 DP 难以解决了,因为状态无论如何都高达 (nm),于是可以考虑组合数直接计算。
考虑合法的方案,相邻的两株幼苗之间至少有一个空位。
拉出 (m-1) 个空位,剩下 (n-m+1) 个位置随便种,然后在每两株幼苗之间插入一个空位,这样一定是合法且唯一的。
所以总方案数就是 (inom{n-m+1}{m}),因为模数是质数所以可以用逆元做,时间复杂度 (O(n+log p))。
对于子任务 6,发现最终的答案就是 (inom{n-m+1}{m} imes m!=frac{(n-m+1)!m!}{m!(n-m+1-m)!}=frac{(n-m+1)!}{(n+1-2m)!}=A_{n-m+1}^m)。
直接算,时间复杂度 (O(m))。
code:
#include<bits/stdc++.h>
using namespace std;
#define N 2005
#define Max(x,y)((x)>(y)?x:y)
#define For(i,x,y)for(i=x;i<=(y);i++)
int n,m,p;
namespace Subtask1
{
inline void init()
{
cout<<1%p;
}
}
namespace Subtask2
{
int tot;
void dfs(int pos,int num)
{
if(pos>n)
{
if(!num)tot++;
return;
}
dfs(pos+1,num);
if(num)dfs(pos+2,num-1);
}
void init()
{
int i;
dfs(1,m);
For(i,2,m)tot*=i;
cout<<tot%p;
}
}
namespace Subtask3
{
int f[205][405],tot;
void init()
{
int i,j,k;
f[0][0]=1;
For(i,1,m)
For(j,(i<<1)-1,n)
For(k,Max((i<<1)-3,0),Max(j-2,0))f[i][j]=(f[i][j]+f[i-1][k])%p;
For(i,(m<<1)-1,n)tot=(tot+f[m][i])%p;
For(i,2,m)tot=1LL*tot*i%p;
cout<<tot;
}
}
namespace Subtask4
{
int f[N][N];
void init()
{
int i,j;
For(i,0,n)f[0][i]=1;
For(i,1,m)
For(j,(i<<1)-1,n)f[i][j]=(f[i][j-1]+f[i-1][Max(j-2,0)]-(!Max((i<<1)-3,0)?0:f[i-1][Max((i<<1)-3,0)-1]))%p;
For(i,2,m)f[m][n]=1LL*f[m][n]*i%p;
cout<<f[m][n];
}
}
namespace Subtask5
{
int tot=1;
int ksm(int x,int y)
{
return(!y?1:1LL*ksm(1LL*x*x%p,y>>1)*(y&1?x:1)%p);
}
int C(int x,int y)
{
int tmp=1,i;
For(i,2,y)tmp=1LL*tmp*i%p;
For(i,2,x-y)tmp=1LL*tmp*i%p;
tmp=ksm(tmp,p-2);
For(i,2,x)tmp=1LL*tmp*i%p;
return tmp;
}
void init()
{
int i;
For(i,2,m)tot=1LL*tot*i%p;
cout<<1LL*C(n-m+1,m)*tot%p;
}
}
namespace Subtask6
{
int P(int x,int y)
{
int tot=1;
while(y--)tot=1LL*tot*x--%p;
return tot;
}
inline void init()
{
cout<<P(n-m+1,m);
}
}
int main()
{
int type;
cin>>type>>n>>m>>p;
switch(type)
{
case 0:Subtask1::init();
break;
case 1:Subtask2::init();
break;
case 2:Subtask3::init();
break;
case 3:Subtask4::init();
break;
case 4:Subtask5::init();
break;
case 5:Subtask6::init();
break;
}
return 0;
}
分包写了,应该很清楚吧 qwq。
以上是关于P5520 [yLOI2019] 青原樱的主要内容,如果未能解决你的问题,请参考以下文章