jzoj5813. 【NOIP提高A组模拟2018.8.14】 计算

8 篇文章 0 订阅

这里写图片描述
这里写图片描述

这道题目dalao们说数据还可以加强,但是鉴于博主太菜,只会做原题数据。
首先我们只考虑第一个限制
那么分成三类
A:这些x的乘积小于 nm n m
B:这些x的乘积等于 nm n m
C:这些x的乘积大于 nm n m
容易知道A,C的数量是一样的,因为对于每一个A,一定存在一个C使得他们乘积是等于 n2m n 2 m
这就是本题的重要突破口。
易知,所有情况为 n2m n 2 m
那么我们只需求出有多少个
(x1,x2,x3,......x2m) ( x 1 , x 2 , x 3 , . . . . . . x 2 m ) 满足
xi ∏ x i = nm n m
我们可以发现,对于每个n的质因子p,假设它在n中出现e次,设aj表示 xj x j 是它的多少次幂。
那么
2mi=1ai=e ∑ i = 1 2 m a i = e
那么我们对于每个质因子,做一遍dp
fi,j f i , j 表示做到第i个数,前j个数选数和为j

code

#include<cstdio>
#include<algorithm>
#include<math.h>
#include<cstring>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long ll;
const int mo=998244353;
int f[205][4000],n,m,p[35000],e[35000],cnt;
ll s1,s2=1ll,s3,s4,x=1ll;
ll power(ll a,int b){
    ll t=1ll,y=a%mo;
    while (b){
        if (b&1) t=t%mo*y%mo;
        y=y%mo*y%mo;
        b=b/2;
    }
    return t%mo;
}
int main()
{
    freopen("count.in","r",stdin);
    freopen("count.out","w",stdout);
    scanf("%d%d",&n,&m);
    int mx=sqrt(n);
    int t=n;
    fo(i,2,mx){
        if (t%i==0){
            p[++cnt]=i;
            while (t%i==0){
                e[cnt]++;
                t=t/i;
            }
            x=x*(1+e[cnt]);
        }
    }
    if (t!=1){
        p[++cnt]=t;
        e[cnt]=1;
        x=x*2;
    }
    s4=power(x,2*m);
    fo(l,1,cnt){
        memset(f,0,sizeof(f));
        fo(i,0,e[l]) f[1][i]=1;
        fo(i,2,2*m)
            fo(j,0,e[l]*m)
                fo(k,0,min(e[l],j))
                    f[i][j]=(f[i][j]+f[i-1][j-k])%mo;
        s2=s2*f[2*m][m*e[l]]%mo;
    }
    ll inv=power(2,mo-2);
    s1=(s4-s2)*inv%mo;
    s1=((s1%mo)+mo)%mo;
    printf("%lld",(s1+s2)%mo);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值