[NOIP模拟10.24][容斥原理]Silhouette

版权声明:蒟蒻写的..能不能吱一声呀 https://blog.csdn.net/Rose_max/article/details/83349531

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
A , B A,B 排序,显然这样对答案没有影响。判断最大值是否相等即可判断无解
我们考虑枚举 A , B A,B 中所有数 S S ,每次确定最大值是 S S 的这片区域的方案数
先考虑总最大值为 S S 的情况,显然这样的区域是一个 a b a*b 的矩形
f [ i ] f[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 [ 0 ] = 1 k f [ k ] f[0]=\sum-1^kf[k]
再考虑 S S 不是最大值的情况
画图可知这样的区域可能是 L L 形或者矩形
我们发现, L L 形可能产生非法情况的只有在中间交界处的那个矩形
因为上面的行更大,不可能非法。右边的列更大,也不可能非法
设这个矩形是 a b a*b 的,上面还有 c c 行,右边还有 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
左边处理的是一个 ( a + c ) b (a+c)*b 的矩阵,右边处理的是一个 a d a*d 的矩阵
同样容斥 f [ 0 ] = 1 k f [ k ] f[0]=\sum-1^kf[k] 可以知道答案
复杂度 n l o g n 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;
}


猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/83349531