[20191005机房测试] Silhouette

有一个n × n的网格,在每个格子上堆叠了一些边长为1的立方体
现在给出这个三维几何体的正视图和左视图,求有多少种与之符合的堆叠立方体的方案
两种方案被认为是不同的,当且仅当某个格子上立方体的数量不同
输出答案对1e9 + 7取模的结果。

给出的是这一坨正方体们的正视图和左视图
开始想的是先求出每一个位置可能的数量范围
求出全集,然后减去每一行/列不符合的拼法
然而这样减了会减多,于是再加上多减的……这就是容斥了

时间复杂度巨大,根本没有过的可能

于是我们考虑确定从某一个方向看过去的视角符合题意
此时我们再容斥即可

容斥的式子不想推了,还得写总结呢

不过题解的方法是真的秀,比我之前的方法快一倍……

代码:

#include<bits/stdc++.h>
#define N 100005
#define ll long long
#define mod 1000000007
using namespace std;

ll xx1,xx2,yy1,yy2;
ll n,ans=1,a[N],b[N],c[N<<1],m;

ll qpow(ll n,ll k)
{
    ll res=1;
    while(k)
    {
        if(k&1) res=(res*n)%mod;
        n=(n*n)%mod;
        k>>=1;
    }
    return res;
}

ll fac[N],invfac[N];

inline void init()
{
    fac[0]=1;
    for(register int i=1;i<=N-3;++i) fac[i]=(fac[i-1]*i)%mod;
    invfac[N-4]=qpow(fac[N-4],mod-2);
    for(register int i=N-5;i>=0;--i) invfac[i]=((i+1)*invfac[i+1])%mod;
    sort(a+1,a+n+1);
    sort(b+1,b+n+1);
    sort(c+1,c+m+1);
}

ll C(ll n,ll m) {return ((fac[n]*invfac[m])%mod*invfac[n-m])%mod;}

template<class T>inline void read(T &res)
{
    char c;T flag=1;
    while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0';
    while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag;
}

ll cal(ll a,ll b,ll c,ll d,ll s)
{
    ll res=0;
    for(register ll i=0;i<=a;++i)
    {
        ll sum=C(a,i)*qpow(qpow(s,i)*((qpow(s+1,a+c-i)-qpow(s,a+c-i)+mod)%mod)%mod,b)%mod;
        sum=sum*qpow(qpow(s,i)*qpow(s+1,a-i)%mod,d)%mod;
        if(i&1) res=(res-sum+mod)%mod;
        else res=(res+sum)%mod;
    }
    return res;
}

int main()
{
    freopen("silhouette.in","r",stdin);
    freopen("silhouette.out","w",stdout);
    read(n);
    for(register int i=1;i<=n;++i)
    {
        read(a[i]);
        c[++m]=a[i];
    }
    for(register int i=1;i<=n;++i)
    {
        read(b[i]);
        c[++m]=b[i]; 
    }
    init();
    if(a[n]!=b[n]) {puts("0");return 0;}
    m=unique(c+1,c+m+1)-(c+1);
    xx1=xx2=n+1;
    yy1=yy2=n;
    for(int i=m;i>=1;i--)
    {
        while(a[yy1-1]==c[i]&&yy1>1) yy1--;
        while(b[yy2-1]==c[i]&&yy2>1) yy2--;
        ans=(ans*cal(xx1-yy1,xx2-yy2,n-xx1+1,n-xx2+1,c[i])%mod);
        xx1=yy1;
        xx2=yy2;
    }
    printf("%lld\n",ans);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/tqr06/p/11625473.html
今日推荐