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