新千题计划 4#:[洛谷 4714]「数学」约数个数和

「数学」约数个数和【难度:NOIP D1T2】求数 n n 的 (所有因数的)k 因数个数和。

本人在洛谷发了题解,此处表住不提。事实上部分数据因数极大(诸如 19260817 乘 998244353 此类),Pollad’s Rho 算法无用。以下代码非正解,而是 WinXP 利用数据漏洞的解法

(由于看不懂正解,暂时留坑)

#include <cstdio>
#include <cstdlib>
#include <algorithm>
typedef long long int LINT;
const LINT MOD = 998244353, MAJC = 64, MAXP = 100000, MAXN = 1000000033;
LINT n, k, jc = 1, zc = 0, inv[MAJC], zs[MAXP], ans = 1; bool hs[MAXP];

LINT Gcd(LINT u, LINT v) { return v? u: Gcd(u % v, v); }

LINT Slp(LINT a, LINT b, LINT m) {
 LINT re; if(b == 1) return a % m;
 re = Slp(a, b >> 1, m); re = re * re % m;
 if(b & 1) return a % m * re % m; else return re; }

inline bool Zsp(LINT u) {
 static const LINT AR[12] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37};
 LINT v = u - 1, cnt = 0, j; if(!(u & 1) && u != 2) return false;
 while(!(v & 1)) { v >>= 1; cnt++; }
 for(int i = 0; i < 12; i++) {
  LINT a = std::min(AR[i], u - 2); LINT w = Slp(a, v, u);
  if(w == 1 || w == u - 1) continue;
  for(j = 1; j < cnt; j++) { w = w * w % u; if(w == u - 1) break; }
  if(j == cnt) return false; } return true; }

inline void Wrk(LINT p) {
 LINT cnt = 0; LINT re = 1; if(n % p) return;
 while(!(n % p)) n /= p, cnt++;
 for(int i = 0; i < cnt; i++) re = (cnt + k + 1 - i) % MOD * re % MOD;
 ans = re * inv[cnt] % MOD * ans % MOD; }

int main() {
 scanf("%lld%lld", &n, &k);
 for(int i = 1; i < MAJC; i++) jc = jc * i % MOD;
 inv[MAJC - 1] = Slp(jc, MOD - 2, MOD);
 for(int i = MAJC - 1; i; i--) inv[i - 1] = i * inv[i] % MOD;

 for(int i = 2; i < MAXP; i++) {
  if(!hs[i]) zs[zc++] = i;
  for(int j = 0; j < zc && i * zs[j] < MAXP; j++) {
   hs[i * zs[j]] = true; if(!(i % zs[j])) break; }}

 for(int i = 0; i < zc && n != 1; i++) Wrk(zs[i]);
 if(n != 1 && Zsp(n)) Wrk(n);
 if(n != 1 && !(n % 998244353))  Wrk(998244353);
 if(n != 1 && !(n % 1000000007)) Wrk(1000000007);
 if(n != 1 && !(n % 1000000009)) Wrk(1000000009);
 if(n != 1) ans = inv[1] % MOD * ((2 + k % MOD) % MOD)
  % MOD * ans % MOD;
 printf("%lld", ans); }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值