nssl1176-轨道【数论,Dp】

正题


题目大意

给出n,m,kn,m,kn,m,k
v=∏i=1nai(ai∈N+,ai&lt;=m)k(gcd(v,k)=1)v=\frac{\prod_{i=1}^na_i(a_i\in N_+,a_i&lt;=m)}{k}(gcd(v,k)=1)v=ki=1nai(aiN+,ai<=m)(gcd(v,k)=1)
aaa的方案个数mod 10007mod\ 10007mod 10007的值


解题思路

fi,jf_{i,j}fi,j表示前i个数的乘积和k的最大公约数为k的第j个约数时的方案个数。
动态转移方程:
fi,j=∑k=1prcj%prck=0fi−1,k∗f1,prcnprcj/prckf_{i,j}=\sum_{k=1}^{prc_j\%prc_k=0}f_{i-1,k}*f_{1,prcn_{prc_j/prc_k}}fi,j=k=1prcj%prck=0fi1,kf1,prcnprcj/prck
prciprc_iprci为k的第i个约数,prcniprcn_iprcni为i是k的第几个约数。
然后我们考虑如何求出1∼m1\sim m1m内有多少个数与k的最大公约数为k的第i个约数
也就是∑i=1m(gcd(i,k)==d)(d∣n)\sum_{i=1}^m (gcd(i,k)==d)(d|n)i=1m(gcd(i,k)==d)(dn)
首先
gcd(i,k)=d⇒gcd(i/d,k)=1gcd(i,k)=d\Rightarrow gcd(i/d,k)=1gcd(i,k)=dgcd(i/d,k)=1(数论基础)
我们可以考虑用容斥,我们将重复偶数次的减去,重复奇数次的加上。
之后预处理一下prci  mod  prcj==0prc_i\ \ mod\ \ prc_j==0prci  mod  prcj==0的情况就好了。


code

#pragma GCC optimize(2)
%:pragma GCC optimize(3)
%:pragma GCC optimize("Ofast")
%:pragma GCC optimize("inline")
%:pragma GCC optimize("-fgcse")
%:pragma GCC optimize("-fgcse-lm")
%:pragma GCC optimize("-fipa-sra")
%:pragma GCC optimize("-ftree-pre")
%:pragma GCC optimize("-ftree-vrp")
%:pragma GCC optimize("-fpeephole2")
%:pragma GCC optimize("-ffast-math")
%:pragma GCC optimize("-fsched-spec")
%:pragma GCC optimize("unroll-loops")
%:pragma GCC optimize("-falign-jumps")
%:pragma GCC optimize("-falign-loops")
%:pragma GCC optimize("-falign-labels")
%:pragma GCC optimize("-fdevirtualize")
%:pragma GCC optimize("-fcaller-saves")
%:pragma GCC optimize("-fcrossjumping")
%:pragma GCC optimize("-fthread-jumps")
%:pragma GCC optimize("-funroll-loops")
%:pragma GCC optimize("-fwhole-program")
%:pragma GCC optimize("-freorder-blocks")
%:pragma GCC optimize("-fschedule-insns")
%:pragma GCC optimize("inline-functions")
%:pragma GCC optimize("-ftree-tail-merge")
%:pragma GCC optimize("-fschedule-insns2")
%:pragma GCC optimize("-fstrict-aliasing")
%:pragma GCC optimize("-fstrict-overflow")
%:pragma GCC optimize("-falign-functions")
%:pragma GCC optimize("-fcse-skip-blocks")
%:pragma GCC optimize("-fcse-follow-jumps")
%:pragma GCC optimize("-fsched-interblock")
%:pragma GCC optimize("-fpartial-inlining")
%:pragma GCC optimize("no-stack-protector")
%:pragma GCC optimize("-freorder-functions")
%:pragma GCC optimize("-findirect-inlining")
%:pragma GCC optimize("-fhoist-adjacent-loads")
%:pragma GCC optimize("-frerun-cse-after-loop")
%:pragma GCC optimize("inline-small-functions")
%:pragma GCC optimize("-finline-small-functions")
%:pragma GCC optimize("-ftree-switch-conversion")
%:pragma GCC optimize("-foptimize-sibling-calls")
%:pragma GCC optimize("-fexpensive-optimizations")
%:pragma GCC optimize("-funsafe-loop-optimizations")
%:pragma GCC optimize("inline-functions-called-once")
%:pragma GCC optimize("-fdelete-null-pointer-checks")
#include<cstdio>
#include<cmath>
#include<algorithm>
#define BPM 10007
#define N 4010
using namespace std;
int n,m,k,frct,prit,fft[N],sum,m1;
int pri[N],frc[N],ff[N][N],ys[10000001],f[N][N];
void dfs(int x,int zf,int ans)//容斥
{
	if(x>prit) {
		sum+=m1/ans*zf;
		return;
	}
	dfs(x+1,zf,ans);
	dfs(x+1,-zf,ans*pri[x]);
}
int main()
{
	scanf("%d%d%d",&n,&m,&k);
	int sk=sqrt(k);
	for(int i=1;i<=sk;i++)
	{
		if(k%i==0)
		{
		  frc[++frct]=i;
		  if(k/i>sk) frc[++frct]=k/i;
		}
	}//求约数
	sort(frc+1,frc+1+frct);
	int tmp=k;
	for(int i=2;i<=sk;i++)
	{
		if(tmp==1) break;
		if(tmp%i==0)
		{
		  pri[++prit]=i;
		  while(tmp%i==0) tmp/=i;
		}
	}//求质因子
	if(tmp!=1) pri[++prit]=tmp;
	sort(pri+1,pri+tmp+1);
	for(int i=1;i<=frct;i++)
	{
		ys[frc[i]]=i;
		sum=0;m1=m/frc[i];
		dfs(1,1,1);
		f[1][i]=sum%BPM;
	}//计算f[1]
	for(int i=1;i<=frct;i++)
	  for(int j=1;j<=i;j++)
	    if(frc[i]%frc[j]==0)
	      ff[i][++fft[i]]=j;//预处理关系
	for(int i=2;i<=n;i++)
	  for(int j=1;j<=frct;j++)
	  {
	  	  if(!fft[j]) continue;
	  	  for(int k=1;k<=fft[j];k++)
	  	    f[i][j]=(f[i][j]+f[i-1][ff[j][k]]*f[1][ys[frc[j]/frc[ff[j][k]]]])%BPM;
	  	    //动态转移
	  }
	printf("%d",f[n][frct]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值