其他分享
首页 > 其他分享> > LOJ6378 「是男人就过8题——Pony.ai」EquationsAndInequations

LOJ6378 「是男人就过8题——Pony.ai」EquationsAndInequations

作者:互联网

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

标签:LOJ6378,Pony,limits,ai,sum,int,str,mul,return
来源: https://www.cnblogs.com/cjoierShiina-Mashiro/p/12543151.html