由题意可得出递推式(f[i ,j]=sum_{ein S} f[i-1,frac{j}{e}]),初值(f[0,0]=1),答案为(f[n,x]),具体意义不表。
分析可知(f[1,e(ein S)]=1),(f[i,ab]=sum_{ain S,bin S}f[i-1,a]f[1,b]);
设模数(m)(指数)的一个原根为(g),构造(e'=log_g(e)in S', ein S),改写递推式(f[1,e'in S']=1),(f[i,a'+b']=sum_{a',bin S'}f[i-1,a']f[1,b']) 。就能套卷积做了*(e)*。
做法的正确性:因为(g^i(0le i<m-1))能取遍([1,m-1])所有数,故(ein S)都有存在唯一在([0,m-1))里的离散对数。
于是此题就是离散快速傅利叶的模板了。
最后谈谈(g)的求法很暴力,枚举原根(g),然后小大枚举阶(阶的个数是(O(sqrt M))级的)来判断是否过早地产生循环,如下
int getG(int m) {
vector<int> r;
for(int i=2; i*i<=m-1; ++i) if((m-1)%i==0) {
r.push_back(i);
if(i*i!=m-1) r.push_back((m-1)/i);
}
sort(r.begin(),r.end());
for(int i=2; ; ++i) {
bool flag=1;
for(auto rr: r) if(fpow(i,rr,m)==1) {flag=0; break;}
if(flag) return i;
}
}
就酱,实现留坑。