Date:2022.02.13
题目描述
设集合N=M={x∣∈N+,x<=k,k∈N+}N=M=\{x|\in N_+,x<=k,k\in N_+\}N=M={x∣∈N+,x<=k,k∈N+}
设f为N到M的映射。
求满足:
f[f(x)]=x的不同的映射ff的个数,由于答案较大,输出答案对14233333取余的数即可。
输入格式
输入一个正整数k
输出格式
输出满足f[f(x)]=x的不同的映射ff的个数对14233333取余得到的数。
输入输出样例
输入 #1复制
3
输出 #1复制
4
说明/提示
四个映射分别为:
f(1) f(2) f(3)
1 2 3
1 3 2
2 1 3
3 2 1
数据范围:
对于20%的数据,1<=k<=91<=k<=91<=k<=9
对于其它的80%的数据,1<=k<=1071<=k<=10^71<=k<=107
内存20MB…(一开始开1MB把自己坑了)
题意解释:N、M集合中分别有kkk个数,之间可两两配对(每个元素不可重复配对在>=2对中)或自己配对(或者理解为不配对,反正占用1种情况)。
思路:设状态方程为:f[i]f[i]f[i]:集合N、M中有iii个数时符合条件的映射数。
f[f[x]]==xf[f[x]]==xf[f[x]]==x即表示映射的关系,因此只能有两种分类:
①f[x]==x−>f[f[x]]==xf[x]==x -> f[f[x]]==xf[x]==x−>f[f[x]]==x,即xxx的映射即为自己(或者说xxx无映射),这显然是1种情况。对答案贡献为f[i−1]∗1f[i-1]*1f[i−1]∗1。
②f[x]==y&&f[y]==xf[x]==y \&\& f[y]==xf[x]==y&&f[y]==x,这体现为N、M的映射关系(可看为一个X形状的交叉)。对答案贡献为f[i−2]∗(i−1)f[i-2]*(i-1)f[i−2]∗(i−1)【即第iii个与(1,i−1)(1,i-1)(1,i−1)中任一个配对,因此(i−1)(i-1)(i−1)种配对情况;至于为什么是f[i−2]f[i-2]f[i−2]?个人认为更好理解的是:我们关心的无非是在前面(1,i−1)(1,i-1)(1,i−1)中选中的是否在之前已配对?如果未配对,直接配对,那么这样(1,i−1)(1,i-1)(1,i−1)中就转化为i−2i-2i−2个元素的配对问题,顺序显然影响不了什么,因此完全可等价为f[i−2]f[i-2]f[i−2](尽管不一定是前i−2i-2i−2个,但完全可以等价);如果已配对,相当于拆散了这个配对,使被选择的和iii配对,原来与被选择的元素配对的元素当然可以再找其它配对呀,剩下的理由同上,仍可以等价为f[i−2]f[i-2]f[i−2]】。
因此状态转移方程:f[i]=f[i−1]+f[i−2]∗(i−1);f[i]=f[i-1]+f[i-2]*(i-1);f[i]=f[i−1]+f[i−2]∗(i−1);
初始状态:f[0]==1f[0]==1f[0]==1;(相当于无法配对或给自己配对,看怎么理解了) f[1]=2;f[1]=2;f[1]=2;(不配对或X形状配对)。【这里为了方便滚动数组取模,iii都减了1,对应的实际意义应为f[i+1]f[i+1]f[i+1]】。
除此之外,空间太小了,显然开不下1e7,滚动数组优化下(不然喜提re
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N = 1010,mod=14233333;
typedef long long LL;
LL n,m,p,k,f[3];
int main()
{
cin>>k;f[0]=1;f[1]=2;LL res=2;
for(int i=3;i<=k;i++)
{
f[res]=(f[(res-1+3)%3]+f[(res-2+3)%3]*(i-1)+mod)%mod;
res++;res%=3;
}
cout<<f[(k-1+3)%3];
return 0;
}
博客详细解析了洛谷P3795题目的解题思路,主要涉及动态规划的概念。通过设立状态方程f[i]表示有i个数时满足条件的映射数,分析两种情况:映射到自身和形成交叉映射,并给出状态转移方程。最后,博主提到由于内存限制,使用滚动数组进行优化。
136

被折叠的 条评论
为什么被折叠?



