求多項式 \(\prod_^n(x+i)\) 的係數在模 \(p\) 意義下的分布,對 \(998244353\) 取模。
\(p\) 為質數。
\(n\leq ^,p\leq 250000\)
我們只計算 \([1,p-1]\) 的分布,最後再算出 \(0\) 的出現次數。
記 \(n1=\lfloor\frac\rfloor,n2=n\bmod p\)。若 \(n\bmod p=p-1\),則 \(n1=\lfloor\frac\rfloor+1,n2=0\)。
\[\begin
&\prod_^n(x+i)\\
=&x^\prod_^(x+i)^\prod_^(x+i)
\end
\]第一部分我們直接忽略。
對於第二部分,\(\prod_^(x+i)=x^-1\)(因為左右兩邊的根都是 \(1,2,\ldots,p-1\))。那麼 \(x^i(p-1)\) 項的係數就是 \(\binom^\)。
因為係數的模數為 \(p\),所以可以用 lucas 定理。
\(\binom\equiv\prod_i\binom\pmod p\)
假設 \(n1=(a_1a_2\ldots a_m)_p\)。
對每一位構造乙個多項式 \(a(x)\),\(a_i\) 表示有多少種方案滿足這一位的貢獻是 \(i\)。
那麼可以像數字dp一樣,列舉 \(i\) 的前多少位和 \(n1\) 是相同的,然後求出後面的方案數。
因為每一位都不能超過 \(a_i\),所以直接把每一位對應的多項式乘在一起就好了。
這裡的卷積稍微有點不同,\(a_i=\sum_\sum_[jk\bmod p=i]b_jc_k\),只需要把下標取離散對數就好了。
不要忘記處理 \(^\)。
複雜度為 \(o(p\log_pn\log p)=o(p\log n)\)。
對於第三部分,可以用倍增+任意模數fft求出整個多項式。
大概就是記 \(f(n,x)=\prod_^n(x+i)\),那麼 \(f(2n+1,x)=f(2n,x)(x+2n+1)\),\(f(2n,x)=f(n,x)f(n,x+n)\)。
記 \(f(n,x)=\sum_ia_ix^i\),那麼 \(f(n,x+n)=\sum_ia_i(x+n)^i=\sum_ia_i\sum_x^jn^\binom=\sum_x_i\sum_a_jn^\binom\),直接卷積即可。
複雜度為 \(o(p\log p)\)。
由於第二部分的多項式形如 \(\sum_ia_ix^\),而第三部分的次數 \(,所以兩部分的乘積不互相干擾,可以分開求出後再合併到一起。
總時間複雜度為 \(o(p(\log n+\log p))\)。
#include#include#include#include#include#include#include#include#include//using namespace std;
using std::min;
using std::max;
using std::swap;
using std::sort;
using std::reverse;
using std::random_shuffle;
using std::lower_bound;
using std::upper_bound;
using std::unique;
using std::vector;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef std::pairpii;
typedef std::pairpll;
void open(const char *s)
void open2(const char *s)
int rd()dowhile((c=getchar())>='0'&&c<='9');return b?-s:s;}
void put(int x)static int c[20];int t=0;while(x)while(t)putchar(c[t--]+'0');}
int upmin(int &a,int b)return 0;}
const ll p1=998244353;
const int n=530000;
const db pi=acos(-1);
ll fp(ll a,ll b,ll p)
ll n,p,g;
ll n1,n2;
ll e1[n],e2[n];
namespace fft
}; cp operator +(cp a,cp b)
cp operator -(cp a,cp b)
cp operator *(cp a,cp b)
cp operator /(cp a,int b)
cp muli(cp a)
cp divi(cp a)
cp conj(cp a)
const int w=524288;
cp w[n];
int rev[n];
void init()
for(int i=2;i<=n;i<<=1)
for(int j=0;j=y&&y>=0?fac[x]*ifac[y]%p*ifac[x-y]%p:0;
}int check()
} return 0;
}void getg()
} else
reverse(a2,a2+(n>>1)+1);
fft::mul(a1,a2,a3,n>>1,n>>1,n>>1,p);
reverse(a3,a3+(n>>1)+1);
for(int i=0;i<=n>>1;i++)
a3[i]=a3[i]*ifac[i]%p;
fft::mul(s,a3,s,n>>1,n>>1,n,p);
} }void gao() }
namespace gao2
ans[1]=1;
for(int j=1;j<=t;j++)
}}ll ans[n];
int main()
gao1::gao();
gao2::gao();
fft::mul2(gao1::ans,gao2::ans,ans,p,p1);
ans[0]=(n+1)%p1;
for(int i=1;ians[0]=(ans[0]-ans[i])%p1;
for(int i=0;ireturn 0;
}
集訓隊作業2018 喂鴿子
設 f n 表示有 n 只鴿子,每次等概率選乙隻喂,期望餵飽第一只鴿子的時間,f 表示有 n 只鴿子,已經喂了 m 次,此時這 n 只鴿子中沒有鴿子被餵飽的概率。ans sum n 1 f i f n sum sum f frac sum f sum frac 注意到有 dfrac n sum x ...
集訓隊作業2018 小Z的禮物
小水題。題意就是不斷隨機放乙個 1 times 2 骨牌,然後取走裡面的東西。求期望多少次取走所有的東西。然後有一維很小。首先顯然 minmax 容斥,將最後取走轉化為欽定一些物品,求第乙個取走的期望。然後顯然第乙個取走的期望只和剩下能蓋到物品的骨牌數有關。乙個骨牌能蓋到物品只和相鄰的兩個格仔是否欽...
集訓隊作業2018 GAME(並查集)
題意 題解 把這個dp式子給列出來 f i si max j f i s i max j fi si jmax 把這個字尾max max max記為m mm的話,每次就是m max m max m m max,考慮對於初始的每個m mm都維護一下,發現是條折線,維護一下這個折線,每次可以把小的一半合...