大概看到題的時候就會做了。好厲害的題。
組合數模質數p等於某值的方案數,很容易想到利用盧卡斯定理。然後要使p進製下每一位對出的結果的乘積在模p意義下為某值,數字dp一波就好。
暴力轉移是每位p^2的,但是轉移的形式是c[i*j]+=a[i]*b[j],可以考慮找原根r,這就變成了c[logri+logrj]+=a[logri]*b[logrj],這裡ntt就好了,模數還剛好是998244353。
然後你讓我寫。就很麻煩了。
先是一波高精度處理。找原根並預處理階。在階的基礎上轉換卷積形式以及ntt板子。哦還有預處理一波階乘來求組合數。最後就是數字dp。
寫還有調搞得我心力憔悴。
**:
#include
#include
#include
#define ll long
long
#define awd 998244353
int p;
struct
bigint
n,l,r;
void
read
(bigint&a)
intoperator
%(bigint
a,int b)
bigint
operator
/(bigint
a,int b)
while
(a.len>
1&&!a.v[a.len]) a.len--;
return a;
}bigint
incr
(bigint
a)if
(a.v[a.len]>=10)
return a;
}bool
zero
(bigint
a)void
trs(bigint&a)
for(
int i=
1;i<=n;i++) a.v[i]=b[i];
a.len=n;
}void
exp0
(bigint&a,
int l)
int kth[
30005
],rk[
30005
],r;
void
findr
() rk[kth[i]]=i;}if
(!flag)
rk[1]=
0;return;}
}llpw(
llx,
lly)
llntt
(ll*a,
int n,
int d)
for(k=
2;k<=n;k<<=1)
}}}ll
t1[65555
],t2[
65555
];void
multi
(int
*a,int
*b,int
*res)
//for(int i=0;i//for(int i=0;ifor
(int i=
1;iint l=
1,invl;
while
(l) l<<=
1;invl=
pw(l<<=1,-
1);for(
int i=p-1
;i//for(int i=0;i//for(int i=0;intt
(t1,l,1);
ntt(t2,l,1);
for(
int i=
0;i(t1[i]*=t2[i])%=awd;
ntt(t1,l,-1);
for(
int i=
0;i//for(int i=0;ifor
(int i=
1;ifor(
int i=
0;i(res[kth[i%(p-1
)]]+=t1[i])%=awd;
res[
0]=res0;
//for(int i=0;i}
int fac[
30005
],inv[
30005
];intc(
int n,
int m)
int l,dp[
105][
30005
],tmp[
30005
],cur;
void
init()}
void
solve
(bigint
a,int
*ans)
//printf("solved\n");
}int ans1[
30005
],ans2[
30005
];int
main
()
UOJ275 清華集訓2016 組合數問題
組合數 cm n cnm 表示的是從 n n 個物品中選出 m role presentation style position relative m m個物品的方案數。舉個例子,從 1 2,3 1,2,3 三個物品中選擇兩個物品可以有 1 2 1,3 2 3 1,2 1,3 2,3 這三種選擇方法...
UOJ 275 清華集訓2016 組合數問題
試題描述 組合數 c n m 表示的是從 n 個物品中選出 m 個物品的方案數。舉個例子,從 1,2,3 三個物品中選擇兩個物品可以有 1,2 1,3 2,3 這三種選擇方法。根據組合數的定義,我們可以給出計算組合數 c n m 的一般公式 begin c n m frac notag end 其中...
UOJ 275 清華集訓2016 組合數問題
組合數 c n m 表示的是從 n 個物品中選出 m 個物品的方案數。舉個例子,從 1,2,3 1,2,3 三個物品中選擇兩個物品可以有 1,2 1,3 2,3 這三種選擇方法。根據組合數的定義,我們可以給出計算組合數 c m n 的一般公式 c n m frac 其中 n 1 2 n 額外的,當 ...