Link
https://www.luogu.org/problemnew/show/P4714
Description
給定 ,計算
Analysis
「你們競賽就學這個啊?太簡單了吧。」
這個式子很醜啊 你又不好化要是好化那直接a了
這種情況下,你要不考慮從實際意義分析,要不考慮從小情況開始
很明顯每多一層 就會有一些東西被重複計數
是 什 麼 呢 ?
舉例吧。
推起來感覺很生成函數
……(雖然實際上算的並不是這個——
多套一層
我們考慮
→ 4 + 3 + 2 + 1
→ (4+3+2+1) + (3+2+1) + (2+1) + 1
¿
發現是一種 次前綴和的形式 ← 這是一個經典問題
所以一個 被求和 次之後產生的貢獻是一個 次前綴和
次前綴和的話,任意某個位置上的結果都是組合數
如果忘記具體的形式,畫轉移矩陣弄冪或者找規律打表都可以直接搞出答案
(貌似也可以直接用矩陣加速(反正都逃不過大數分解。。。
如果你沒推過
好吧,怎麼推?上面那個式子看着很可以搞事情啊
要求的東西是
考慮
→ 1
→ 4
這種情況下我們可以看作有一堆點從 出發
求到達 的方案數。
我們假設 在某個詭異的(?)座標系裏的座標
那麼。
每次 必定 +1
每次 必定不變小
所以。相當於求
經典問題,用插板就可以解決。
更簡單地
啥意思?
的時候很顯然,就是在 個 裏面選一個啊。 就更不用說了。
呢?相當於是在 個空裏插 個板(空代表0到n次冪,插一個空就選了這個冪)
你問我怎麼是插板?首先插板插下去的是無序的,所以可以一律當成是從(冪)大到小插進去的
這樣的話就相當於(可重複地)插這麼些個闆闆,一種插板方案對應了展開之後的一個因子
以上。
舉個例子吧。
你隨便插一下
就相當於是:
第一次展開 的因子
第二次展開 的因子
第三次展開 的因子
這就是一種方案。
代碼就比較精污了,你不得不上Pollard-ρ+Miller-Rabbin來分解N
回憶一下啊
Miller-Rabbin ① 於是做費馬素性檢測
② 二次探測 或者
選取前 ⑨ 個素數(~23) 作爲費馬素性檢測的 即可。
Pollard-ρ:忘了
利用 生成僞隨機數列
利用循環節碰撞最小素因子 (沒辦法搞 所以得單獨做)
客觀存在數列 由生日悖論,循環節期望出現位置
具體:用兩個指針 和 在 上走
等一個 且 此時找到 的一個(有用噠)因子
按步批量處理gcd加速。
實際上並不需要嚴格分解成多個素數冪的乘積。儘量偷懶嗷
另外還可以先用 以內的素數篩 然後剩下的一定是
然後……搞一搞??玄學
話說我一開始寫的超假的miller rabbin居然只掛了一個點。。。我這個pollardrho好像也有一點假
我的 碼力 怎麼 這麼 差 啊 啊 啊
下面是 仍然可能有鍋的代碼
這個選手的代碼可以拿去當wc題讓人找錯 論寫一道題出幾十個bug是什麼感受
提醒一下,long double乘法取模最後要%p+p%p
不要問我爲什麼,雖然我覺着理論上它不會出負數。。。不過既然這是事實
我就煤辦法臘()
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<cctype>
#include<ctime>
using namespace std;
const long long p = 998244353;
const int MAXN = 100;
int Id[MAXN];
long long n, k, Pi[MAXN], Ai[MAXN], Pk[MAXN], Ak[MAXN];
int Prime[9] = {2, 3, 5, 7, 11, 13, 17, 19, 23};
long long gcd(const long long& a, const long long& b)
{
return !b?a:gcd(b,a%b);
}
long long Mul(long long a, long long b, const long long& p)
{
static long long t;
t = (long double) a * b / p;
return ((a * b - t * p) % p + p) % p;
}
long long qpowm(long long a, long long b, const long long& p)
{
if (b <= 0) return 1;
long long ret = 1;
while (b)
{
if (b & 1) ret = Mul(ret, a, p);
a = Mul(a, a, p);
b >>= 1;
}
return ret;
}
long long PowList[100];
bool Miller(const long long& n)
{
if (n == 2 || n == 3 || n == 5 || n == 7 || n == 11 || n == 13 || n == 17 || n == 19 || n == 23) return 1;
if (n < 23) return 0;
register bool flag;
register long long sub = n - 1;
while (!(sub&1)) sub >>= 1;
for (register long long t, gkd, i = 0; i < 9; ++i)
{
gkd = sub; PowList[0] = 0; t = qpowm(Prime[i], gkd, n);
while (gkd <= n - 1)
{
PowList[++PowList[0]] = t;
t = Mul(t, t, n);
gkd <<= 1;
}
if (PowList[PowList[0]] != 1) return 0;
for (register int j = PowList[0] - 1; j >= 1; --j)
{
if (PowList[j] == n - 1) break;
if (PowList[j] != 1) return 0;
}
}
return 1;
}
long long Pollard_Find(const long long& n)
{
register long long alph = 1, x, y, LastX, LastY, Step = pow(n, 0.1), Prod;
while (true)
{
x = 2; y = 2;
while (true)
{
LastX = x; LastY = y; Prod = 1;
for (register long long i = 1; i <= Step; ++i)
{
x = Mul(x, x, n); x += alph; if (x >= n) x -= n;
y = Mul(y, y, n); y += alph; if (y >= n) y -= n;
y = Mul(y, y, n); y += alph; if (y >= n) y -= n;
Prod = Mul(Prod, abs(x-y), n);
}
Prod = gcd(Prod, n);
if (Prod == 1) continue;
if (Prod != n) return Prod;
x = LastX; y = LastY;
for (register long long i = 1; i <= Step; ++i)
{
x = Mul(x, x, n); x += alph; if (x >= n) x -= n;
y = Mul(y, y, n); y += alph; if (y >= n) y -= n;
y = Mul(y, y, n); y += alph; if (y >= n) y -= n;
Prod = gcd(n, abs(x-y));
if (Prod == n) break;
if (Prod != 1) return Prod;
}
break;
}
++alph;
}
}
void Pollard_Rho(const long long& n)
{
if (n <= 1) return;
if (Miller(n)) { Pi[++Pi[0]] = n, ++Ai[Pi[0]]; return;}
long long k = Pollard_Find(n);
Pollard_Rho(k); Pollard_Rho(n/k);
}
inline bool cmp(const int& a, const int& b)
{
return Pi[a] < Pi[b];
}
int main()
{
scanf("%lld%lld", &n, &k);
if (!(n&1))
{
Pi[++Pi[0]] = 2, Ai[1] = 1; n >>= 1;
while (!(n&1)) n>>=1, ++Ai[Pi[0]];
}
Pollard_Rho(n);
for (register int i = 1; i <= Pi[0]; ++i)
{
Id[i] = i;
}
sort(Id + 1, Id + 1 + Pi[0], cmp);
if (Pi[0]) Pk[++Pk[0]]=Pi[Id[1]], Ak[1]=Ai[Id[1]];
for (register int i = 2; i <= Pi[0]; ++i)
{
if (Pi[Id[i]] == Pi[Id[i-1]]) ++Ak[Pk[0]];
else Pk[++Pk[0]] = Pi[Id[i]], Ak[Pk[0]] = Ai[Id[i]];
}
long long Ans = 1;
for (register int i = 1; i <= Pk[0]; ++i)
{
for (register long long x = 1; x <= Ak[i]; ++x)
{
Ans = Mul(Ans, k + 1 + x, p);
Ans = Mul(Ans, qpowm(x, p - 2, p), p);
}
}
printf("%lld", Ans);
return 0;
}