洛谷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;	 
}
posted @ 2022-11-09 16:37  nxhx  阅读(42)  评论(0)    收藏  举报
1 2 3
4