zoukankan      html  css  js  c++  java
  • [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\%$的数据:$Pleqslant 1,000$
    对于另$10\%$的数据:$P$为质数。
    对于所有数据:
    $1leqslant nleqslant 50$
    $1leqslant mleqslant 1,000$
    $2leqslant Pleqslant {10}^9$
    $0leqslant 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(nsigma(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++

  • 相关阅读:
    ansible 批量在远程主机上执行命令
    SQLAlchemy
    operator, itertools
    mongodb基础语法
    django model Meta选项
    __getattr__,settr
    django的contenttype表
    time和datetime和tzinfo
    全局钩子的改名
    dom中文字居中
  • 原文地址:https://www.cnblogs.com/wzc521/p/11551087.html
Copyright © 2011-2022 走看看