LGP5520
PS:数学太差了,简单组合数虐我出sh**t.
T:给定 n 个位置,要求放下 m个互不相同的东西,两两之间不能相邻,求方案数对p取摸ans.
S:对于前4个子任务考虑dp,先不考虑编号,f[ i ][ j ]表示前 i 个数,且第 i个数放在j位置的方案数,考虑转移:f[ i ][ j ] =Σ f[ i -1 ][ k ],{ 1≤k≤j - 2 }.注意初始化,f[ 1 ][ k] = 1{1≤k≤m}
同时我们注意转移Σf[ i - 1 ][ k ]我们可以使用前缀和优化,最后乘m!(全排列).喜提60pts.
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define re register int ty,n,m,mod,ans,num=1,f[2010][2010],sum[2010][2010]; inline int fd(){ int s=1,t=0; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') s=-1; c=getchar(); } while(c>='0'&&c<='9'){ t=t*10+c-'0'; c=getchar(); } return s*t; } int main() { // freopen("T1.in","r",stdin); // freopen("T1.out","w",stdout); ty=fd(),n=fd(),m=fd(),mod=fd(); for(re int i=1;i<=n;++i){ f[1][i]=1; sum[1][i] = (sum[1][i-1]%mod + f[1][i]%mod)%mod; } for(re int i=2;i<=m;++i) for(re int j=1;j<=n;++j){ if(j>=3) f[i][j] = (f[i][j]%mod + sum[i-1][j-2]%mod)%mod; sum[i][j] = (sum[i][j-1]%mod + f[i][j]%mod)%mod; } for(re int i=1;i<=n;++i) ans = (ans%mod + f[m][i]%mod)%mod; for(re int i=1;i<=m;++i) num = (1ll * num * i)%mod; ans = (1ll*ans%mod * num%mod)%mod; printf("%d",ans); return 0; }
对于满分做法考虑组合数,m棵树,最少用m-1个隔板,我们只要在剩下n-m+1个位置摆m棵树,因为有m-1个隔板,移动刻板位置可保证Cmn-m+1 方案合法,最后乘上m!即可.
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define re register int ty,n,m,mod,ans=1; inline int fd(){ int s=1,t=0; char c=getchar(); while(c<'0'||c>'9'){ if(c=='-') s=-1; c=getchar(); } while(c>='0'&&c<='9'){ t=t*10+c-'0'; c=getchar(); } return s*t; } int main() { freopen("T1.in","r",stdin); freopen("T1.out","w",stdout); ty=fd(),n=fd(),m=fd(),mod=fd(); for(re int i=n-2*m+2;i<=n-m+1;++i) ans = (1ll*ans%mod*i%mod)%mod; printf("%d",ans); return 0; }