Description
有一个n n的网格,在每个格子上堆叠了一些边长为1的立方体。 现在给出这个三维几何体的正视图和左视图,求有多少种与之符合的堆叠立方体的方
案。两种方案被认为是不同的,当且仅当某个格子上立方体的数量不同。 输出答案对109 + 7取模的结果。
Sample Input
2
1 2
2 1
Sample Output
5
题解
容易发现,其实就是要求这样一个方程的整数解数量
∀ i ∈ [ 1 , n ] , m a x ( x j , i ) = A j , m a x ( x j , i ) = B i \forall i\in[1,n] ,max(x_{j,i})=A_j,max(x_{j,i})=B_i ∀i∈[1,n],max(xj,i)=Aj,max(xj,i)=Bi
将 A , B A,B A,B排序,显然这样对答案没有影响。判断最大值是否相等即可判断无解
我们考虑枚举 A , B A,B A,B中所有数 S S S,每次确定最大值是 S S S的这片区域的方案数
先考虑总最大值为 S S S的情况,显然这样的区域是一个 a ∗ b a*b a∗b的矩形
设 f [ i ] f[i] f[i]表示至少有 i i i行不合法的方案数(保证列全部合法)
有转移
f [ i ] = ∑ C a i ∗ ( S i ∗ ( ( S + 1 ) a − i − S a − i ) ) b f[i]=\sum C_{a}^{i}*(S^i*((S+1)^{a-i}-S^{a-i}))^b f[i]=∑Cai∗(Si∗((S+1)a−i−Sa−i))b
.简单容斥可知答案
f [ 0 ] = ∑ − 1 k f [ k ] f[0]=\sum-1^kf[k] f[0]=∑−1kf[k]
再考虑 S S S不是最大值的情况
画图可知这样的区域可能是 L L L形或者矩形
我们发现, L L L形可能产生非法情况的只有在中间交界处的那个矩形
因为上面的行更大,不可能非法。右边的列更大,也不可能非法
设这个矩形是 a ∗ b a*b a∗b的,上面还有 c c c行,右边还有 d d d列
有转移
f [ i ] = ∑ C a i ∗ ( S i ∗ ( ( S + 1 ) a + c − i − S a + c − i ) ) b ∗ ( S i ∗ ( ( S + 1 ) a − i − S a − i ) ) d f[i]=\sum C_{a}^i*(S^i*((S+1)^{a+c-i}-S^{a+c-i}))^b*(S^i*((S+1)^{a-i}-S^{a-i}))^d f[i]=∑Cai∗(Si∗((S+1)a+c−i−Sa+c−i))b∗(Si∗((S+1)a−i−Sa−i))d
左边处理的是一个 ( a + c ) ∗ b (a+c)*b (a+c)∗b的矩阵,右边处理的是一个 a ∗ d a*d a∗d的矩阵
同样容斥 f [ 0 ] = ∑ − 1 k f [ k ] f[0]=\sum-1^kf[k] f[0]=∑−1kf[k]可以知道答案
复杂度 n l o g n nlogn nlogn
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#include<bitset>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define mod 1000000007
using namespace std;
inline int read()
{
int f=1,x=0;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(int x){write(x);puts("");}
LL pow_mod(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1)ret=ret*a%mod;
a=a*a%mod;b>>=1;
}
return ret;
}
LL inv[110000],pre[110000];
LL C(int n,int m){return pre[n]*inv[m]%mod*inv[n-m]%mod;}
LL solve(LL a,LL b,LL c,LL d,LL s)
{
LL ret=0;
for(int i=0;i<=a;i++)
{
LL sum=C(a,i)*pow_mod(pow_mod(s,i)*((pow_mod(s+1,a+c-i)-pow_mod(s,a+c-i)+mod)%mod)%mod,b)%mod;
sum=sum*pow_mod(pow_mod(s,i)*pow_mod(s+1,a-i)%mod,d)%mod;
if(i&1)ret=(ret-sum+mod)%mod;
else ret=(ret+sum)%mod;
}
return ret;
}
int s1[110000],s2[110000],tt[210000],ln;
int n;
int main()
{
pre[0]=1;for(int i=1;i<=100000;i++)pre[i]=pre[i-1]*i%mod;
inv[100000]=pow_mod(pre[100000],mod-2);
for(int i=99999;i>=0;i--)inv[i]=inv[i+1]*(i+1)%mod;
n=read();
for(int i=1;i<=n;i++)s1[i]=read(),tt[++ln]=s1[i];
for(int i=1;i<=n;i++)s2[i]=read(),tt[++ln]=s2[i];
sort(s1+1,s1+1+n);sort(s2+1,s2+1+n);
sort(tt+1,tt+1+ln);ln=unique(tt+1,tt+1+ln)-(tt+1);
if(s1[n]!=s2[n])return puts("0"),0;
int lst1=n+1,lst2=n+1,u1=n,u2=n;
LL ans=1;
for(int i=ln;i>=1;i--)
{
while(s1[u1-1]==tt[i]&&u1>1)u1--;
while(s2[u2-1]==tt[i]&&u2>1)u2--;
ans=(ans*solve(lst1-u1,lst2-u2,n-lst1+1,n-lst2+1,tt[i])%mod);
lst1=u1;lst2=u2;
}
pr2(ans);
return 0;
}