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

###Description
这里写图片描述

###Input
一行由空格隔开的两个整数,分别是 n 和 m。

###Output
一行表示答案。

###Sample Input
Input1:
6 1
Input2:
6 3

###Sample Output
Output1:
10
Output2:
2248

###Data Constraint
这里写图片描述

###Hint
第一个样例中,合法的方案有 (1, 1),(1, 2),(1, 3),(1, 6),(2, 1),(2, 2),(2, 3),(3, 1),(3, 2),(6, 1) 共 10 种。

###题解
一看题,艾玛,一道神仙题。心凉了一大截。

还是无脑地上暴力吧。最后爆0。往事不堪回首
咳咳,直接讲正解。
题意:要求找出m*2个数的集合满足集合中的每个数可以整除n且集合中每个数的乘积小于n^m的方案。
然后,直接求不好求。
我们发掘一下一些神奇的性质。
我们设
A表示集合小于n^m的方案
B表示集合等于n^m的方案
C表示集合大于n^m的方案

那么对于一个{x 1,x 2,x 3,……,x m2}令乘积小于n^m
那么就把这个集合反一下:
{n/x 1,n/x 2,n/x 3,……,n/x m
2}
那么它的乘积大于n^m

于是可以发现,一个集合乘积小于nm,必然对应一个集合乘积大于nm
那么,显而易见地发现:A=C
因为,A+B+C=yueshuhe(n)^(2m)
那么,A=(yueshuhe(n)^(2m)-B)/2

这条式子比较优美了。
那么我们就可以求满足集合乘积=n^m的方案就得到答案。

我们分解n=p[i]^q[i]
那么对于每个数的质因数中,他们的和等于q[i]*m
这就是一个背包问题嘛。
先枚举当前到第l个质因数
设f[i,j]表示当前到集合中的第i个数,它分解质因数中质因数为第l个的指数的和为j的方案数。
直接转移即可。

顺利解决问题。
###代码

uses math;
var
        i,j,k,l,n,m,u,x,y:longint;
        ans,ano,mo:int64;
        a:array[1..10000,1..6] of longint;
        bz:array[1..1000000] of boolean;
        p,q,op:array[0..100000] of longint;
        now:array[1..6] of longint;
        f:array[0..10000,0..3000] of int64;
function ksm(a,b:int64):int64;
var
        t,y:int64;
begin
        t:=1;
        y:=a;
        while b<>0 do
        begin
                if(b and 1)=1 then
                        t:=(t*y) mod mo;
                y:=(y*y) mod mo;
                b:=b shr 1;
        end;
        exit(t);
end;
begin
        assign(input,'count.in');reset(input);
        assign(output,'count.out');rewrite(output);
        mo:=998244353;
        readln(n,m);
        for i:=2 to 1000000 do
        begin
                if not bz[i] then
                begin
                        inc(op[0]);
                        op[op[0]]:=i;
                        for j:=2 to 1000000 div i do
                        begin
                                bz[j*i]:=true;
                        end;
                end;
        end;
        u:=n;
        for i:=1 to op[0] do
        begin
                if op[i]>u then
                begin
                        break;
                end;
                if u mod op[i]=0 then
                begin
                        inc(p[0]);
                        p[p[0]]:=op[i];
                        q[p[0]]:=1;
                        u:=u div op[i];
                end;
                while u mod op[i]=0 do
                begin
                        inc(q[p[0]]);
                        u:=u div op[i];
                end;
        end;
        for i:=1 to p[0] do q[i]:=q[i]*m;
        ans:=1;
        for l:=1 to p[0] do
        begin
        fillchar(f,sizeof(f),0);
        f[0,0]:=1;
        for i:=1 to 2*m do
        begin
                for j:=0 to q[l] do
                begin
                        for k:=0 to min(j,q[l] div m) do
                        begin
                                f[i,j]:=(f[i,j]+f[i-1,j-k]) mod mo;
                        end;
                end;
        end;
        ans:=(ans*f[2*m,q[l]]) mod mo;
        end;
        ano:=0;
        for i:=1 to trunc(sqrt(n)) do
        begin
                if n mod i=0 then
                begin
                        ano:=ano+1;
                        if sqr(i)<n then ano:=ano+1;
                end;
                //ano:=(ano*((ksm(p[i],q[i]+1)-1)*ksm(p[i]-1,mo-2)) mod mo) mod mo;
        end;
        ans:=ans+ksm(ano,2*m);
        writeln((ans*ksm(2,mo-2)) mod mo);
end.
我活在这夜里。无论周围多么黑暗,我都要努力发光!我相信着,终有一天,我会在这深邃的夜里,造就一道最美的彩虹。
原文地址:https://www.cnblogs.com/RainbowCrown/p/11148397.html