zoukankan      html  css  js  c++  java
  • P5824 十二重计数法

    十二重计数法 ×

    刻刻帝 十二种子弹 √


    以下复杂度均在已经预处理完逆元、阶乘逆元和阶乘的情况下计算。

    咋一股 这玩意的味道。。。不过简单多了

    1. 球之间互不相同,盒子之间互不相同。

    显然是 (m^n)​​​。复杂度 (O(log n))​。

    ll Aleph(){return qpow(m,n);}
    
    1. 球之间互不相同,盒子之间互不相同,每个盒子至多装一个球。

    一个一个放,所以是 (m^underline n)​​。复杂度 (O(n))​。

    ll Bet(){
    	ll ret=1;
    	rep(i,m-n+1,m)ret=ret*i%P;
    	return ret;
    }
    
    1. 球之间互不相同,盒子之间互不相同,每个盒子至少装一个球。

    对 1 考虑做容斥,所以答案是

    [sum_{i=0}^m(-1)^iinom{m}{i}(m-i)^n ]

    复杂度 (O(mlog n))​​。

    另外你也可以考虑用斯特林数,答案就是 (egin{Bmatrix}n\mend{Bmatrix} imes m!)​​,这里采用的是前面的做法。

    ll Gimel(){
    	ll ret=0;
    	rep(i,0,m)
    		if(i&1)ret=(ret-C(m,i)*qpow(m-i,n)%P+P)%P;
    		else ret=(ret+C(m,i)*qpow(m-i,n)%P)%P;
    	return ret;
    }
    
    1. 球之间互不相同,盒子全部相同。

    枚举非空盒子个数,所以是

    [sum_{i=1}^{m}egin{Bmatrix}n\mend{Bmatrix} ]

    来一发 第二类斯特林数·行,求个前缀和即可。复杂度 (O(nlog n)-O(1))​​​​​(固定 (n))。

    void Zaphkiel(){
    	vec f(n+1),g(n+1);
    	rep(i,0,n){
    		f[i]=1ll*qpow(i,n)*invfac[i]%P;
    		g[i]=invfac[i];
    		if(i&1)g[i]=P-g[i];
    	}
    	S=mul(f,g,n<<1);
    	S.resize(n+1);
    }
    ll Dalet(){
    	ll ret=0;
    	rep(i,1,min(m,n))ret=(ret+S[i])%P;
    	return ret;
    }
    

    同时第三题的代码也可以简化为:

    ll Gimel(){return 1ll*(m>n?0:S[m])*fac[m]%P;}
    
    1. 球之间互不相同,盒子全部相同,每个盒子至多装一个球。

    显然是 ([nle m])​​。复杂度 (O(1))​​。

    ll He(){return (n<=m);}
    
    1. 球之间互不相同,盒子全部相同,每个盒子至少装一个球。

    显然是 (egin{Bmatrix}n\mend{Bmatrix})​​​​​,可以使用通项(不过也可以用 4 中算的整),复杂度 (O(nlog m)/O(nlog n)-O(1))​​​​(固定 (n))。

    ll Vav(){return S[m];}
    
    1. 球全部相同,盒子之间互不相同。

    小学奥数插板法可知为 (dbinom{n+m-1}{m-1})​​,复杂度 (O(1))​。

    ll Zayin(){return C(n+m-1,m-1);}
    
    1. 球全部相同,盒子之间互不相同,每个盒子至多装一个球。

    显然是 (dbinom{m}{n})​,复杂度 (O(1))​。

    ll Het(){return C(m,n);}
    
    1. 球全部相同,盒子之间互不相同,每个盒子至少装一个球。

    小学奥数插板法可知为 (dbinom{n-1}{m-1})​,复杂度 (O(1))​​。

    ll Tet(){return C(n-1,m-1);}
    
    1. 球全部相同,盒子全部相同。

    本题唯一有点意思的东西。所以另外十一题放这干啥,搁这十二合一恶心人呢

    考虑一个经典的 dp:(f_{i,j}) 表示 (i) 个球,(j)​​ 个盒子。那么容易得到

    [f_{i,j}=f_{i,j-1}+f_{i-j,j} ]

    那么考虑设 (F_j(x))({f_{i,j}}_{i=0}^{infty}) 的 OGF,可得:

    [egin{aligned} [x^i]F_j(x)&=[x^i]F_{j-1}(x)+[x^{i-j}]F_j(x)\ F_j(x)&=F_{j-1}(x)+x^jF_j(x)\ F_j(x)&=F_{j-1}(x)frac{1}{1-x^j}\ F_j(x)&=prod_{i=1}^{j}frac{1}{1-x^j}\ ln F_k(x)&=-sum_{i=1}^kln(1-x^i)\ ln F_k(x)&=-sum_{i=1}^ksum_{j=1}^{infty}frac{x^{ij}}{j} end{aligned} ]

    暴力计算出 (ln F_m(x))​​​ 对其求 exp 即可,复杂度 (O(nlog n)-O(1))​​​(固定 (m))。

    void Zaphkiel(){
        ...
    	rep(i,0,n)f[i]=0;
    	rep(i,1,m)for(ll j=1;i*j<=n;j++)f[i*j]=(f[i*j]+inv[j])%P;
    	getexp(f,F,n+1);
    }
    ll Yod(){return F[n];}
    
    1. 球全部相同,盒子全部相同,每个盒子至多装一个球。

    显然是 ([nle m])。复杂度 (O(1))

    ll Yod_Alef(){return (n<=m);}
    
    1. 球全部相同,盒子全部相同,每个盒子至少装一个球。

    每个盒子扔掉一个球就变成了 10。复杂度 (O(nlog n)-O(1))(固定 (m)​)。

    ll Yod_Bet(){return n<m?0:F[n-m];}
    

    最后缝合一下就是完整代码了,如下:

    // Problem: P5824 十二重计数法
    // Contest: Luogu
    // URL: https://www.luogu.com.cn/problem/P5824
    // Memory Limit: 256 MB
    // Time Limit: 2000 ms
    // 
    // Powered by CP Editor (https://cpeditor.org)
    
    #include<bits/stdc++.h>
    #define endl '
    ' 
    #define rep(i,a,b) for(ll i=(a);i<=(b);++i)
    #define Rep(i,a,b) for(ll i=(a);i>=(b);--i)
    using namespace std;
    typedef long long ll;
    inline void chkmax(ll &x,ll y){if(x<y)x=y;}
    inline void chkmin(ll &x,ll y){if(x>y)x=y;}
    struct IO_Tp {
        const static int _I_Buffer_Size = 2 << 22;
        char _I_Buffer[_I_Buffer_Size], *_I_pos = _I_Buffer;
    
        const static int _O_Buffer_Size = 2 << 22;
        char _O_Buffer[_O_Buffer_Size], *_O_pos = _O_Buffer;
    
        IO_Tp() { fread(_I_Buffer, 1, _I_Buffer_Size, stdin); }
        ~IO_Tp() { fwrite(_O_Buffer, 1, _O_pos - _O_Buffer, stdout); }
    
        IO_Tp &operator>>(ll &res) {
            ll f=1;
            while (!isdigit(*_I_pos)&&(*_I_pos)!='-') ++_I_pos;
            if(*_I_pos=='-')f=-1,++_I_pos;
            res = *_I_pos++ - '0';
            while (isdigit(*_I_pos)) res = res * 10 + (*_I_pos++ - '0');
            res*=f;
            return *this;
        }
    
        IO_Tp &operator<<(ll n) {
            if(n<0)*_O_pos++='-',n=-n;
            static char _buf[10];
            char *_pos = _buf;
            do
                *_pos++ = '0' + n % 10;
            while (n /= 10);
            while (_pos != _buf) *_O_pos++ = *--_pos;
            return *this;
        }
    
        IO_Tp &operator<<(char ch) {
            *_O_pos++ = ch;
            return *this;
        }
    } IO;
    ll n,m;
    typedef vector<int> vec;
    const int N=4194304,P=998244353;
    int inv[N],fac[N],invfac[N],pw[N];
    namespace Poly{
        const int G=3,img=86583718;
        int lmt,rev[N];
        inline int qpow(int a,int k){
            int ret=1;
            while(k){
                if(k&1)ret=1LL*ret*a%P;
                a=1LL*a*a%P;
                k>>=1;
            }
            return ret%P;
        }
        inline void init(int n){
            lmt=1;int t=0;
            while(lmt<n)lmt<<=1,t++;
            for(int i=1;i<lmt;i++)rev[i]=(rev[i>>1]>>1)|(i&1)<<(t-1);
        }
        inline void NTT(vec&A,int lmt,int tp){
            if(A.size()<lmt)A.resize(lmt);
            for(int i=0;i<lmt;i++)if(i<rev[i])swap(A[i],A[rev[i]]);
            for(int m=1,t=0;m<lmt;m<<=1,t++)
                for(int j=0,Wn=pw[t+1];j<lmt;j+=m<<1)
                    for(int k=0,w=1,x,y;k<m;k++,w=1LL*w*Wn%P)
                        x=A[j+k],y=1LL*w*A[j+k+m]%P,A[j+k]=(x+y)%P,A[j+k+m]=(x-y+P)%P;
            if(tp==1)return;
            reverse(A.begin()+1,A.begin()+lmt);
            for(int i=0,inv=qpow(lmt,P-2);i<lmt;i++)A[i]=1LL*A[i]*inv%P;
        } 
        vec mul(vec f,vec g,int len){
            init(len);
            f.resize(lmt),g.resize(lmt);
            NTT(f,lmt,1);NTT(g,lmt,1);
            for(int i=0;i<lmt;i++)f[i]=1LL*f[i]*g[i]%P;
            NTT(f,lmt,-1);
            return f;
        } 
        void getinv(vec&f,vec&g,int len){
            if(f.size()<(len<<2))f.resize(len<<2);
            if(g.size()<(len<<2))g.resize(len<<2);
            if(len==1){g[0]=qpow(f[0],P-2);return;}
            getinv(f,g,len+1>>1);
            init(len<<1);
            vec c(lmt);
            copy(f.begin(),f.begin()+len,c.begin());
            NTT(c,lmt,1),NTT(g,lmt,1);
            for(int i=0;i<lmt;i++)g[i]=1LL*(2LL-1LL*g[i]*c[i]%P+P)%P*g[i]%P;
            NTT(g,lmt,-1);
            for(int i=len;i<lmt;i++)g[i]=0;
        }
        vec getdev(vec f,int len){
            vec g(len-1);
            for(int i=1;i<len;i++)g[i-1]=1LL*i*f[i]%P;
            return g;
        }
        vec getinvdev(vec f,int len){
            vec g(len+1);
            for(int i=1;i<len;i++)g[i]=1LL*f[i-1]*inv[i]%P;
            return g;
        }
        vec getln(vec f,int len){
            vec a=getdev(f,len),b;
            getinv(f,b,len);
            return getinvdev(mul(a,b,len<<1),len);
        }
        void getexp(vec f,vec&g,int len){
            if(g.size()<(len<<2))g.resize(len<<2);
            if(len==1){g[0]=1;return;}
            getexp(f,g,len+1>>1);
            init(len<<1);
            vec d=getln(g,len),e(f.begin(),f.begin()+len);
            NTT(g,lmt,1),NTT(d,lmt,1),NTT(e,lmt,1);
            for(int i=0;i<lmt;i++)g[i]=1LL*(1-d[i]+e[i]+P)*g[i]%P;
            NTT(g,lmt,-1);
            for(int i=len;i<lmt;i++)g[i]=0;
        }
        vec getpow(vec f,int len,int k){
            vec g(len),h=getln(f,len);
            for(int i=0;i<len;i++)h[i]=1LL*h[i]*k%P;
            getexp(h,g,len);
            return g;
        }
    }
    using namespace Poly;
    vec S,F;
    int Kurumi(int n){
        int lmt=1;
        inv[0]=inv[1]=1;
        while(lmt<n)lmt<<=1;
        for(int i=2;i<lmt;i++)inv[i]=1LL*(P-P/i)*inv[P%i]%P;
        fac[0]=invfac[0]=1;
        for(int i=1;i<lmt;i++)fac[i]=1LL*fac[i-1]*i%P,invfac[i]=1LL*invfac[i-1]*inv[i]%P;
        pw[23]=Poly::qpow(Poly::G,119);
        for(int i=22;i>=0;i--)pw[i]=1LL*pw[i+1]*pw[i+1]%P;
        return lmt;
    }
    ll C(ll n,ll m){return 1ll*fac[n]*invfac[m]%P*invfac[n-m]%P;}
    void Zaphkiel(){
        vec f(n+1),g(n+1);
        rep(i,0,n){
            f[i]=1ll*qpow(i,n)*invfac[i]%P;
            g[i]=invfac[i];
            if(i&1)g[i]=P-g[i];
        }
        S=mul(f,g,n<<1);
        S.resize(n+1);
        rep(i,0,n)f[i]=0;
        rep(i,1,m)for(ll j=1;i*j<=n;j++)f[i*j]=(f[i*j]+inv[j])%P;
        getexp(f,F,n+1);
    }
    ll Aleph(){return qpow(m,n);}
    ll Bet(){
        ll ret=1;
        rep(i,m-n+1,m)ret=ret*i%P;
        return ret;
    }
    ll Gimel(){return 1ll*(m>n?0:S[m])*fac[m]%P;}
    ll Dalet(){
        ll ret=0;
        rep(i,1,min(m,n))ret=(ret+S[i])%P;
        return ret;
    }
    ll He(){return (n<=m);}
    ll Vav(){return m>n?0:S[m];}
    ll Zayin(){return C(n+m-1,m-1);}
    ll Het(){return C(m,n);}
    ll Tet(){return C(n-1,m-1);}
    ll Yod(){return F[n];}
    ll Yod_Alef(){return (n<=m);}
    ll Yod_Bet(){return n<m?0:F[n-m];}
    int main(){
        IO>>n>>m;
        Kurumi(n<<2);
        Zaphkiel();
        IO<<Aleph()<<endl;
        IO<<Bet()<<endl;
        IO<<Gimel()<<endl;
        IO<<Dalet()<<endl;
        IO<<He()<<endl;
        IO<<Vav()<<endl;
        IO<<Zayin()<<endl;
        IO<<Het()<<endl;
        IO<<Tet()<<endl;
        IO<<Yod()<<endl;
        IO<<Yod_Alef()<<endl;
        IO<<Yod_Bet()<<endl;
        return 0;
    }
    
    
    
    
    

    最后,简单讲一下这题和 more transformations of integer sequences 的关系(不知道的人可以看下 rqy 课件,或者这里也可以):

    1. (operatorname{AIJ}_m(a))​,其中​​ (a_x=1,forall x)​。​​​
    2. (operatorname{AIJ}_m(a)),其中​ (a_1=1,a_x=0,x>1)​。​
    3. (operatorname{AIJ}_m(a))​,其中 (a_1=0,a_x=1,x>1)​​。
    4. (operatorname{AIK}_m(a))​,其中 (a_x=1,forall x)​​。
    5. (operatorname{AIK}_m(a)),其中 (a_1=1,a_x=0,x>1)​。
    6. (operatorname{AIK}_m(a)),其中 (a_x=0,a_x=1,x>1)​。
    7. (operatorname{EIJ}_m(a))​,其中 (a_x=1,forall x)​​。
    8. (operatorname{EIJ}_m(a)),其中 (a_1=1,a_x=0,x>1)
    9. (operatorname{EIJ}_m(a)),其中 (a_x=0,a_x=1,x>1)
    10. (operatorname{EIK}_m(a)),其中 (a_x=1,forall x)
    11. (operatorname{EIK}_m(a)),其中 (a_1=1,a_x=0,x>1)
    12. (operatorname{EIK}_m(a)),其中 (a_x=0,a_x=1,x>1)

    如以上有问题请指出,谢谢。

  • 相关阅读:
    C#中using的使用-以FileStream写入文件为例
    C#中FileStream的对比以及使用方法
    DevExpress的TextEdit、RadioGroup、ColorPickEdit设置默认值
    DevExpress的TextEdit限制输入内容的格式,比如只能输入数字
    CS中委托与事件的使用-以Winform中跨窗体传值为例
    Winforn中怎样在窗体中打开另一个窗体
    Winforn中实现ZedGraph自定义添加右键菜单项(附源码下载)
    Winform中实现ZedGraph的多条Y轴(附源码下载)
    《深入理解Java虚拟机》内存分配策略
    三十而立
  • 原文地址:https://www.cnblogs.com/happydef/p/Tokisaki-Kurumi.html
Copyright © 2011-2022 走看看