[CSP-S模拟测试]:B(DP+数学)

题目传送门(内部题45)


输入格式

第一行$3$个整数$n,m,P$。
第二行$m$个整数,表示$m$次询问。


输出格式

一行$m$个整数表示答案。


样例

样例输入1:

2 4 4
0 1 2 3

样例输出1:

8 2 4 2

样例输入2:

3 3 2333333
1 38 227

样例输出2:

578724625 893056135 887007020


数据范围与提示

样例1解释:

对于第三组询问,四种方案分别为:

$x_0=1,x_1=2$
$x_0=2,x_1=1$
$x_0=2,x_1=3$
$x_0=3,x_1=2$

数据范围:

对于前$20\%$的数据:$n=2$
对于另$30\%$的数据:$P\leqslant 1,000$
对于另$10\%$的数据:$P$为质数。
对于所有数据:
$1\leqslant n\leqslant 50$
$1\leqslant m\leqslant 1,000$
$2\leqslant P\leqslant {10}^9$
$0\leqslant v_i<P$


题解

首先,我们考虑$DP$,定义$dp[i][j]$表示前$i$个变量乘起来取模后结果为$j$的方案数,转移挺简单的,不再赘述。

但是显然跑不过,考虑优化。

打表找规律发现,如果$gcd(a,P)=gcd(b,P)$那么$dp[i][a]=dp[i][b]$。

具体我也不会证,这不怪我,因为出题人也不会。

这样状态数就减少了不少,转移大同小异,注意乘上$\sigma(x)$($x$的约数个数),最后再除掉即可。

直接算可能会$TLE$,我们可以先预处理出来每两个数乘起来是几,注意用$map$即可。

时间复杂度:$\Theta(n\sigma(P)^2)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,m;
long long P;
int Map[1345][1345];
long long dp[51][1345];
long long que[1345],phi[1345];
map<int,int> s;
long long qpow(long long x,long long y)
{
	long long res=1;
	while(y)
	{
		if(y&1)res=res*x%1000000007;
		x=x*x%1000000007;
		y>>=1;
	}
	return res;
}
void pre_work()
{
	for(int i=1;i*i<=P;i++)
		if(!(P%i))
		{
			que[++que[0]]=i;
			if(i*i!=P)que[++que[0]]=P/i;
		}
}
long long get_phi(long long x)
{
	long long res=x;
	for(long long i=2;i*i<=x;i++)
		if(!(x%i))
		{
			res=res/i*(i-1);
			while(!(x%i))x/=i;
		}
	if(x>1)res=res/x*(x-1);
	return res;
}
int main()
{
	scanf("%d%d%lld",&n,&m,&P);
	pre_work();
	for(int i=1;i<=que[0];i++)
	{
		phi[i]=get_phi(P/que[i]);
		s[que[i]]=i;
		dp[1][i]=phi[i];
	}
	for(int i=1;i<=que[0];i++)
		for(int j=1;j<=que[0];j++)
			Map[i][j]=s[__gcd(que[i]*que[j]%P,P)];
	for(int i=2;i<=n;i++)
		for(int j=1;j<=que[0];j++)
			for(int k=1;k<=que[0];k++)
				dp[i][Map[j][k]]=(dp[i][Map[j][k]]+dp[i-1][j]*phi[k]%1000000007)%1000000007;
	while(m--)
	{
		long long x;
		scanf("%lld",&x);
		int gcd=__gcd(P,x);
		printf("%lld ",dp[n][s[gcd]]*qpow(phi[s[gcd]],1000000005)%1000000007);
	}
	return 0;
}

rp++

posted @ 2019-09-19 17:12  HEOI-动动  阅读(170)  评论(0编辑  收藏  举报