题目大意:
有三种颜色的大小相同的正方形积木各A,B,C个,你要在一个n*n大小的地盘上搭起这些积木,问有多少种搭积木的方案使得其主视图只有一种颜色。
对1e9+7取模。A,B,C,n<=25。
题解:
考虑枚举哪一个颜色在最前面,剩下两个没有本质区别(算完后乘一个组合数)。每一列独立,做一个卷积即可得到。因此考虑每一列的情况。
现在要计算某一列放a个1和b个2的答案,枚举高度h,那么正面看去恰好h个1,因此先摆出高度恰好为h的方案,然后钦定这看到的h个是1,剩余的随意组合。
高度恰好为h的方案,相当于n个变量的和等于a+b并且每个数值不超过h并且存在至少一个数值是h。第三个限制可以忽略,就是个经典容斥了。这部分O(n^3)。
复杂度O(n^5),可以用NTT优化第一部分的卷积。
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define gc getchar()
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x,ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
const int A=30,N=30;int fac[A*3+N],facinv[A*3+N],f[A*3][A*3],g[A][A*2],h[N][A][A*2],n,ans,a[10];
inline void upd(int &x,int y) { x+=y,(x>=mod?x-=mod:0); }
inline int sol(int x,int s) { return (s&1)?(x?mod-x:0):x; }
inline void clr(int *a,int n) { memset(a,0,sizeof(int)*(n+1)); }
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
inline int prelude(int n)
{
rep(i,fac[0]=1,n) fac[i]=(lint)fac[i-1]*i%mod;
facinv[n]=fast_pow(fac[n],mod-2);
for(int i=n-1;i>=0;i--) facinv[i]=(i+1ll)*facinv[i+1]%mod;
return 0;
}
inline int C(int n,int m) { if(n<0||m<0||n<m) return 0;return (lint)fac[n]*facinv[n-m]%mod*facinv[m]%mod; }
inline int calc_f(int s,int n)
{
rep(i,0,s)
{
rep(j,0,i) rep(k,0,n) upd(f[i][j],(lint)sol(C(n,k),k)*C(i+n-k*(j+1)-1,n-1)%mod);
for(int j=i;j;j--) f[i][j]-=f[i][j-1],(f[i][j]<0?f[i][j]+=mod:0);
}
return 0;
}
inline int calc_g(int A,int B) { rep(a,0,A) rep(b,0,B) rep(i,0,a) upd(g[a][b],(lint)f[a+b][i]*C(a-i+b,a-i)%mod);return 0; }
inline int calc_h(int A,int B,int n)
{
h[0][0][0]=1;
rep(i,0,n-1) rep(a,0,A) rep(b,0,B) if(h[i][a][b])
rep(c,0,A-a) rep(d,0,B-b) upd(h[i+1][a+c][b+d],(lint)h[i][a][b]*g[c][d]%mod);
return 0;
}
inline int calc(int x,int y,int z) { return (lint)C(a[y]+a[z],a[y])*h[n][a[x]][a[y]+a[z]]%mod; }
int main()
{
a[1]=inn(),a[2]=inn(),a[3]=inn(),n=inn(),sort(a+1,a+4),swap(a[1],a[3]);
prelude(a[1]+a[2]+a[1]+n),calc_f(a[1]+a[2]+a[1],n),
calc_g(a[1],a[1]+a[2]),calc_h(a[1],a[1]+a[2],n);
upd(ans,calc(1,2,3)),upd(ans,calc(2,1,3)),upd(ans,calc(3,1,2));
return !printf("%d\n",ans);
}