洛谷P3795
分析
这道题考虑 dp,因为 \(10^7\) 的数据很容易就把搜索卡死。
观察题目发现,在这道题目中有两种映射方式才可以符合要求:
\[f_i=i
\]
\[f_i=j,f_j=i(i\ne j)
\]
所以说,本题的递推公式也就围绕着这两个公式而形成,我们定义变量 \(i\) 和一个数组 \(dp\),用 \(dp\) 数组来表示有 \(k=i\) 时的答案数,可知:
\[dp_i=dp_{i-2}\times (i-1)+dp_{i-1}
\]
为什么呢?
首先 \(dp_{i-1}\) 代表了新加入的 \(i\) 数符合第一种映射方式,接下来 \(dp_{i-2}\times (i-1)\) 则是新加入的 \(i\) 数与原来的 \(i-1\) 中的任一一数组成的第二种映射。
代码实现
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <queue>
#include <iostream>
#include <string>
using namespace std;
int main(){
int k;
scanf("%d",&k);
long long dp[k+5];
memset(dp,0,sizeof(dp));
dp[1]=1;
dp[2]=2;
for(int i=3;i<=k;i++){
dp[i]=dp[i-2]*(i-1)+dp[i-1];
dp[i]%=14233333;
}
printf("%d",dp[k]);
return 0;
}
当你兴冲冲地提交时,你会发现你寄了……(毕竟只有 \(20MB\))
所以说我们再次观察,发现关于 \(dp_i\) 的大小只跟 \(i-1\) 和 \(i-2\) 有关,所以说,我们选择使用一个滚动数组优化。
AC!
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <string.h>
#include <queue>
#include <iostream>
#include <string>
using namespace std;
int main(){
int k;
scanf("%d",&k);
long long dp[3];
memset(dp,0,sizeof(dp));
dp[0]=1;
dp[1]=2;
if(k==1){
printf("1");
return 0;
}
if(k==2){
printf("2");
return 0;
}
for(int i=3;i<=k;i++){
dp[2]=dp[0]*(i-1)+dp[1];
dp[2]%=14233333;
dp[0]=dp[1];
dp[1]=dp[2];
}
printf("%lld",dp[2]);
return 0;
}

浙公网安备 33010602011771号