秀秀的照片(photo)
题目描述
华华在和秀秀视频时有截很多图。华华发现秀秀的每一张照片都很萌很可爱。为什么会这样呢?华华在仔细看过秀秀的所有照片后,发现秀秀的照片都具有一个相同的性质。
设秀秀的分辨率为m×nm×n,即在水平方向上每一行有mm个像素,垂直方向上每一列有nn个像素,照片共有m×nm×n个像素。每一个像素都有一个颜色,共有kk种颜色。华华宝宝发现无论是沿着哪两列像素的分界线将秀秀的照片分成左右两半(共有m−1m−1种分法),左右两半不同颜色的种数都是相同的。
华华宝宝把自己的发现告诉了秀秀宝宝。现在秀秀想知道当照片分辨率为m×nm×n,像素颜色种数为kk(不一定kk种颜色都出现)的时候,共有多少张不同的照片满足上面的性质。
由于答案可能很大,你只需输出答案对109+7109+7取模的结果即可。
数据范围
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。每个测试点的规模及特点如下表:
测试点编号 |
nn |
mm |
kk |
1 |
n≤4n≤4 |
m≤4m≤4 |
k≤5k≤5 |
2 |
n≤10n≤10 |
||
3 |
n≤4n≤4 |
m≤10m≤10 |
|
4 |
n≤10n≤10 |
k≤10k≤10 |
|
5 |
k≤2000k≤2000 |
||
6 |
n≤100n≤100 |
m≤100m≤100 |
|
7 |
|||
8 |
n≤2000n≤2000 |
m≤2000m≤2000 |
|
9 |
k≤106k≤106 |
||
10 |
solution
坑题,浪费了我好多时间,然后测试垫底了。。
我们考虑边上的两列,他们的颜色数应要相同,且中间的颜色应为他们的交集的子集。
假设中间颜色数为i,两边颜色数为i+j(也就是单独出现j种颜色)
方案数为
意思是先选i颜色,中间每个格子有i种填法
再在剩余的中选j个,再选j个,确定两边
再乘以 i+j个格子填n个物品的方案数·,再忽略格子的顺序(i+j)!,两边配对(^2)
Sij即为第二类斯特林数,表示i个格子放j个物品,且每个格子至少放一个的方案数
如果i单独放一个格子为s[i-1][j-1]
否则为s[i-1][j] 且有j种方法
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 4005
#define ll long long
#define mod 1000000007
using namespace std;
int n,m,k;
ll S[maxn][maxn],jc[1000006],ny[1000006],ans;
ll work(ll a,int num){
ll p=a,wa=1;
while(num){
if(num&1)wa=wa*p;
p=p*p;p%=mod;wa%=mod;num/=2;
}
return wa;
}
ll C(int N,int M){
return jc[N]*ny[M]%mod*ny[N-M]%mod;
}
int main()
{
cin>>n>>m>>k;
int nn=n+n;
S[0][0]=1;
for(int i=1;i<=nn;i++){
for(int j=1;j<=i;j++){
S[i][j]=S[i-1][j-1]%mod+j*S[i-1][j]%mod;
S[i][j]%=mod;
//cout<<S[i][j]<<' ';
}
}
int M=1000000;
jc[0]=1;for(int i=1;i<=M;i++)jc[i]=jc[i-1]*i%mod;
ny[M]=work(jc[M],mod-2);
for(int i=M-1;i>=0;i--)ny[i]=ny[i+1]*(i+1)%mod;
if(m==1){
printf("%lld",work(k,n));return 0;
}
for(int i=0;i<=min(n,k);i++)
for(int j=0;j<=n,k;j++){
if(i+j+j>k)break;if(i+j>n)break;
ll tmp=C(k,i)*C(k-i,j)%mod*C(k-i-j,j)%mod;
tmp=tmp*work(i,(m-2)*n)%mod;
ll t2=S[n][i+j]*jc[i+j]%mod;t2=t2*t2%mod;
ans=ans+tmp*t2%mod;ans%=mod;
}
cout<<ans<<endl;
return 0;
}