CF888D Almost Identity Permutations
题目大意
给出 \(n\) 和 \(k\) 计算满足至少有 \(n-k\) 个位置的值 \(a_i=i\) 的 \(1\cdots n\) 的全排列的个数。
题目分析
反过来想,\(n-k\) 个位置 \(a_i=i\),也就是 \(k\) 个位置 \(a_i\neq i\),即错排问题。
求 \(k\) 个数的错排个数,有递推公式:
\[d_i=(i-1)\times(d_{i-1}+d_{i-2})
\]
\(d_i\) 表示第 \(i\) 个数的错排个数。其中 \(d_1=0\),\(d_2=1\)。
所以我们要在 \(n\) 个位置中选择 \(k\) 个位置放置数,所以答案为 \(C_{n}^{i}\times d_i +1\),其中 \(1\le i\le k\)。
注意最后要加 \(1\),因为我们没有计算 \(k=1\) 时的情况。
注意:
- 记得开 \(\rm long~long\)。
代码
#define int long long
const int ma=1005;
int dp[ma];
int C[ma][ma];
int n,k;
inline void init()
{
C[0][0]=1;
for(register int i=1;i<=1e3;i++)
{
C[i][0]=1;
for(register int j=1;j<=i;j++)
{
C[i][j]=C[i-1][j]+C[i-1][j-1];
}
}
}
#undef int
int main(void)
{
#define int long long
n=read(),k=read();
init();
if(k==1)
{
printf("1\n");
}
else
{
int ans(0);
dp[2]=1;
for(register int i=3;i<=n;i++)
{
dp[i]=(i-1)*(dp[i-1]+dp[i-2]);
}
for(register int i=2;i<=k;i++)
{
ans+=C[n][i]*dp[i];
}
printf("%lld\n",ans+1);
}
return 0;
}

浙公网安备 33010602011771号