zoukankan      html  css  js  c++  java
  • 【题解】P3747 [六省联考2017]期末考试 (单位根反演)

    【题解】P3747 [六省联考2017]组合数问题(单位根反演)

    就是要我们求

    [sum_{i=0}^k {nkchoose ik+r} ]

    换一个形式

    [=sum_{i=0}^{nk} {nkchoose i} [k|i-r] ]

    单位根反演带入

    [={1over k}sum_{i=0}^{nk} {nkchoose i} sum _{j=0}^{k-1} omega_k^{(i-r)j} ]

    凑一个二项式

    [={1over k}sum_{i=0}^{nk} sum_{j=0}^{k-1} {nkchoose i} omega_k^{ij}cdot omega_k^{-rj} ]

    交换和式

    [={1over k}sum_{j=0}^{k-1} omega_k^{-jr} sum_{i=0}^{nk} {nkchoose i} omega_k^{ij} ]

    也就是

    [{1over k}sum_{j=0}^{k-1} omega_k^{-jr} (1+omega_k^j)^{nk} ]

    (这个形式是一个FFT的形式),令(f(x)=(1+x)^{nk}),原式即

    [{1over k} sum_{j=0}^{k-1} omega_k^{-jr} f(omega_k^j) ]

    考虑范德蒙德的逆矩阵,即

    [V_k^{-1}={1 over k}egin{pmatrix} {1}&{1}&{cdots}&{1}\ {1}&{omega_k^{-1}}&{cdots}&{omega_k^{-(k-1)}}\ {1}&{omega_k^{-2}}&{cdots}&{omega_k^{-(k-1)2}}\ {vdots}&{vdots}&{}&{vdots}\ {1}&{omega_k^{-(k-1)}}&{cdots}&{omega_k^{-(k-1)(k-1)}}\ end{pmatrix} ]

    (f(omega_k^j))是一个点值,而({1over k} sum_{j=0}^{k-1} omega_k^{-jr} f(omega_k^j)),就是:由点值构成的行向量([f(omega_k^0) quad f(omega_k^1)dots f(omega_k^{k-1})] imes V_{k}^{-1})的第(r)列的值!也就是(f(x))这个多项式循环卷积(因为我们带入的都是(k)次单位根,于是(f(x) mod x^k-1)意义下的)意义下第(r)项的值。(根据dft和idft的定义)

    然后这里(k)很小,直接暴力卷积即可

    //@winlere
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    
    using namespace std;  typedef long long ll;
    typedef vector<int> poly;
    int n,mod,k,r;
    int MOD(const int&x){return x>=mod?x-mod:x;}
    int MOD(const int&x,const int&y){return 1ll*x*y%mod;}
    poly operator * (poly a,poly b){
    	if(a.empty()||b.empty()) return poly(k,0);
    	poly ret(k);
    	for(int t=0,ed=a.size();t<ed;++t)
    		for(int i=0,ed=b.size();i<ed;++i)
    			ret[(t+i)%k]=MOD(ret[(t+i)%k]+MOD(a[t],b[i]));
    	return ret;
    }
    poly ksm(ll x){
    	poly ret(k,0),b(k,0);
    	ret[0]=1; ++b[0]; ++b[1%k];
    	while(x){
    		if(x&1) ret=ret*b;
    		b=b*b,x>>=1;
    	}
    	return ret;
    }
    int main(){
    	cin>>n>>mod>>k>>r;
    	cout<<ksm(1ll*n*k)[r]<<endl;
    	return 0;
    }
    
    
    
    
  • 相关阅读:
    【题解】国家集训队礼物(Lucas定理)
    【题解】佳佳的斐波那契数列(矩阵)
    【题解】Zap(莫比乌斯反演)
    HNOI2019爆零记
    Emacs配置
    【题解】Journeys(线段树优化连边)
    一直没有敢发的NOIP2018游记
    【题解】Digit Tree
    【题解】BZOJ3489 A Hard RMQ problem(主席树套主席树)
    【题解】大括号
  • 原文地址:https://www.cnblogs.com/winlere/p/12739234.html
Copyright © 2011-2022 走看看