Luogu4161 & Luogu6280 - dp - 数论 -

对于某个排列p,将ipi建个图发现这时对应的答案就是lcm(),注意与环中哪些数无关。

进一步观察可以发现这实际上就是这个问题:从n的排列中分成m个部分,令p=m个部分的size的lcm,求不同p的和/个数
看到lcm可以考虑质因子

先考虑求p的个数:
首先,想让p的个数最大的话,肯定是让size都互质(注意由于可以有多个1,所以size之和可以小于n)(如果两两不互质的话,显然可以这两个数同除gcd,显然这样的话答案一定不会变差,所以以下均默认两两互质,注意1也是互质)
问题就转化为了求这个方案数:p1t1+p2t2+..+pktknpi是从小到大的质数,此时K=lcm(p1t1,...,pktk)=
这个显然可以dp,设dp[i][j]表示考虑到前i个质数,当前和为j的方案数,dp[0][0]=1
考虑到dp[i][j]=k=1pkjdp[i1][jpk](这个转移就相当于加了一个size为pk的集合,其K=lcm(..)多乘了个pk
答案就是dp[pcnt][1..n](因为1的缘故和可以小于n)

至于算和,转移改成dp[i][j]=dp[i1][j]+k=1pkjdp[i1][jpk]pk即可(因为相当于此时答案中所有的K都乘了个pk,因为之前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;
}


posted @   SkyRainWind  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下
点击右上角即可分享
微信分享提示