zoukankan      html  css  js  c++  java
  • [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
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    不同数据类型的取值范围
    反正切函数求圆周率 atan
    HDOJ 1106
    HDOJ 1596
    HDOJ 1026 dfs路径保存
    qsort用法总结
    HDOJ 2088
    HDOJ 1878 欧拉回路 nyoj 42一笔画问题
    HDOJ 1863 prim算法 HDOJ 1879
    HDOj 1010 DFS优化
  • 原文地址:https://www.cnblogs.com/tqr06/p/11625473.html
Copyright © 2011-2022 走看看