Luogu4161 & Luogu6280 - dp - 数论 -
对于某个排列p,将建个图发现这时对应的答案就是,注意与环中哪些数无关。
进一步观察可以发现这实际上就是这个问题:从的排列中分成个部分,令这个部分的size的lcm,求不同p的和/个数
看到lcm可以考虑质因子
先考虑求p的个数:
首先,想让p的个数最大的话,肯定是让size都互质(注意由于可以有多个1,所以size之和可以小于n)(如果两两不互质的话,显然可以这两个数同除gcd,显然这样的话答案一定不会变差,所以以下均默认两两互质,注意1也是互质)
问题就转化为了求这个方案数:,是从小到大的质数,此时
这个显然可以dp,设表示考虑到前i个质数,当前和为j的方案数,
考虑到(这个转移就相当于加了一个size为的集合,其多乘了个)
答案就是(因为1的缘故和可以小于n)
至于算和,转移改成即可(因为相当于此时答案中所有的K都乘了个,因为之前p没有出现过,lcm直接相乘)
代码(6280):
// by SkyRainWind
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
#define mpr make_pair
#define debug() cerr<<"Madoka"<<endl
#define rep(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 10005;
LL dp[2][maxn];
int n,notpm[maxn], pm[maxn], pcnt=0;
void xxs(){
notpm[1] = 1;
for(int i=2;i<=n;i++){
if(!notpm[i])pm[++ pcnt] = i;
for(int j=1;j<=pcnt && i*pm[j] <= n;j++){
notpm[i*pm[j]] = 1;
if(i%pm[j] == 0)break;
}
}
}
signed main(){
int mod;
scanf("%d%d",&n,&mod);
xxs();
dp[0][0] = 1;
for(int i=1;i<=pcnt;i++){
memcpy(dp[i&1], dp[i&1^1], sizeof dp[i&1]);
int pp = pm[i];
while(pp <= n){
for(int j=pp;j<=n;j++)
(dp[i&1][j] += 1ll * dp[i&1^1][j - pp] * pp) %= mod;
pp *= pm[i];
}
}
LL ans = 0;
for(int i=1;i<=n;i++)(ans += dp[pcnt&1][i])%=mod;
printf("%lld\n",ans + 1);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下