zoukankan      html  css  js  c++  java
  • LOJ6378 「是男人就过8题——Pony.ai」EquationsAndInequations

    Link
    我们考虑将原问题划分为两个子问题:
    一、将(k)个变量划分为若干个有序集合,其中同一个集合中的变量相等,顺序在前的集合中的变量更小。
    (g_{i,j})表示考虑划分下标(i)集合中变量,出现的后缀和(指的是集合大小的后缀和)的状态为(j)的方案数,这可以用(O(4^k))的复杂度求出。
    二、再求出由划分后的变量构成(S)的方案数。
    注意到这里已经没有了大小的限制,所以我们可以考虑直接用生成函数解决。
    设划分后的集合为(S_1,cdots,S_m),记(a_i=sumlimits_{j=i}^m|S_j|),那么答案就是(sumlimits_{i=1}^ma_ix_i=S)的正整数解数,即([x^S]prodlimits_{i=1}^mfrac{x^{a_i}}{1-x^{a_i}})
    直接做的复杂度为(O(2^kk^4log S)),注意到所有生成函数的分母都是(F(x)=prodlimits_{i=1}^k1-x^i)的因式,那么我们把所有的生成函数写成(frac{P(x)}{F(x)})的形式即可使用相同的递推式,复杂度为(O(2^kk^2+k^2log S))

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    const int N=4100,M=80,P=1000000007;
    int v,size[N],sum[N],f[N][M],g[N][N],h[M],a[N],b[N],s[M],t[M];
    void inc(int&a,int b){a+=b-P,a+=a>>31&P;}
    int mul(int a,int b){return 1ll*a*b%P;}
    int read(){int x;scanf("%d",&x);return x;}
    int get()
    {
        static char str[5];scanf("%s",str);
        if(str[0]=='<')return str[1]=='='? 4:1;
        if(str[0]=='>')return str[1]=='='? 5:2;
        return str[0]=='='? 3:6;
    }
    void mul(int *p,int *q)
    {
        static int t[M*2];memset(t,0,(v+v+1)<<2);
        for(int i=0;i<=v;++i) if(p[i]) for(int j=0;j<=v;++j) if(q[j]) inc(t[i+j],mul(p[i],q[j]));
        for(int i=v+v;i>v;--i) if(t[i]) for(int j=1;j<=v;++j) inc(t[i-j],mul(t[i],h[j]));
        memcpy(p,t,(v+1)<<2);
    }
    int cal(int i)
    {
        int ans=0;
        for(int j=sum[i];j<=v;++j) inc(ans,mul(f[i][j-sum[i]],s[j]));
        return ans;
    }
    int main()
    {
        for(int i=1;i<4096;++i)
        {
    	size[i]=size[i>>1]+(i&1);
    	for(int j=f[i][0]=1;j<=12;++j)
    	    if(i>>j-1&1)
    	    {
    		sum[i]+=j;
    		for(int k=j;k<=78;++k) inc(f[i][k],f[i][k-j]);
    	    }
        }
        for(int ans,n,k,m,u;scanf("%d%d%d",&k,&n,&m)!=EOF;)
        {
    	u=(1<<n)-1,v=(n+1)*n/2,ans=0,std::fill(a,a+u+1,1),std::fill(b,b+u+1,1),memset(g,0,sizeof g),memset(h,0,(v+1)<<2),memset(s,0,(v+1)<<2),memset(t,0,(v+1)<<2);
    	h[0]=P-1,g[0][0]=1,s[0]=t[1]=1;
    	for(int i=1,o,x,y;i<=m;++i)
    	{
    	    x=read()-1,o=get(),y=read()-1;
    	    if(o==3) for(int j=1;j<=u;++j) if((j>>x&1)^(j>>y&1)) a[j]=0;
    	    if(o==1||o==2||o==6) for(int j=1;j<=u;++j) if(j>>x&j>>y&1) a[j]=0;
    	    if(o==1||o==4) for(int j=1;j<=u;++j) if(~j>>x&j>>y&1) b[j]=0;
    	    if(o==2||o==5) for(int j=1;j<=u;++j) if(j>>x&~j>>y&1) b[j]=0;
    	}
    	for(int i=0;i<=u;++i) for(int j=0;j<=u;++j) if(b[i]&&g[i][j]) for(int s=u^i,k=s;k;k=(k-1)&s) if(a[k]) inc(g[i|k][j|1<<(n-size[i]-1)],g[i][j]);
    	for(int i=1;i<=n;++i) for(int j=v;j>=i;--j) inc(h[j],P-h[j-i]);
    	for(;k;k>>=1,mul(t,t)) if(k&1) mul(s,t);
    	for(int i=1;i<=u;++i) inc(ans,mul(g[u][i],cal(i)));
    	printf("%d
    ",ans);
        }
    }
    
  • 相关阅读:
    Jzoj3899 逻辑的连通性
    第三十九天 how can I 坚持
    第三十八天 how can I 坚持
    第三十七天 how can I 坚持
    第三十六天 how can I 坚持
    第三十五天 how can I 坚持
    第三十四天 how can I 坚持
    第三十三天 how can I 坚持
    第三十二天 how can I 坚持
    逆向iOS SDK -- _UIImageAtPath 的实现(SDK 5.1)
  • 原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12543151.html
Copyright © 2011-2022 走看看