k-size字符串(组合数学)
思路:因为要分成 k k k段,显然字符 a a a与字符 b b b的段数绝对值值差 ≤ 1 \leq1 ≤1
设 a a a分成 i i i段,即: i = k − i , i + 1 = k − i , i − 1 = k − i i=k-i,i+1=k-i,i-1=k-i i=k−i,i+1=k−i,i−1=k−i
2 i − 1 = k , 2 i = k , 2 i + 1 = k 2i-1=k,2i=k,2i+1=k 2i−1=k,2i=k,2i+1=k.
显然当 k k k为偶数时,只有 2 i = k → i = k 2 2i=k\rightarrow i=\dfrac{k}{2} 2i=k→i=2k这种情况。
即 a … b a\dots b a…b或 b … a b\dots a b…a
在 k k k个位置放置相应的一个字符 a a a或 b b b。
接下来就等价于将 n − k 2 n-\dfrac{k}{2} n−2k个数放入 k 2 \dfrac{k}{2} 2k个格子的方式.
也等价于 整数 n − k 2 n-\dfrac{k}{2} n−2k分成 k 2 \dfrac{k}{2} 2k个非负整数的方式。
令 f ( x , y ) f(x,y) f(x,y)为整数x分成 y y y个非负整数的方式。
有 f ( x , y ) = f ( x , y − 1 ) + f ( x − 1 , y ) f(x,y)=f(x,y-1)+f(x-1,y) f(x,y)=f(x,y−1)+f(x−1,y)(这里 x − 1 x-1 x−1是保证第一个格子有数,不是第一个格子只放一个1)
即对应第一个数为0和第一个数不为0之和或者说是第一个格子不放东西和第一个格子放东西的方式之和。
根据观察这是一个组合数的递推:
根据 f ( n , 1 ) = 1 = C n + 1 − 1 n f(n,1)=1=C_{n+1-1}^n f(n,1)=1=Cn+1−1n, f ( 1 , n ) = n = C 1 + n − 1 1 f(1,n)=n=C_{1+n-1}^{1} f(1,n)=n=C1+n−11
C x + y − 1 x = C x + y − 2 x + C x + y − 2 x − 1 C_{x+y-1}^{x}=C_{x+y-2}^{x}+C_{x+y-2}^{x-1} Cx+y−1x=Cx+y−2x+Cx+y−2x−1
所以可得 f ( x , y ) = C x + y − 1 x f(x,y)=C_{x+y-1}^x f(x,y)=Cx+y−1x
最后奇,偶数讨论一下即可得出答案。
需要注意的可能存在组合数的分母或分子 ≤ 0 \leq0 ≤0的情况要舍去。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e5+5,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
ll ksm(ll a,ll n){
ll ans=1;
while(n){
if(n&1) ans=ans*a%mod;
a=a*a%mod;
n>>=1;
}
return ans;
}
ll inv(ll x){
return ksm(x,mod-2);
}
ll C(ll x,ll y){
ll ans=1;
for(int i=1;i<=y;i++) ans=ans*(x-i+1)%mod*inv(i)%mod;
return ans;
}
ll f(ll x,ll y){
if(y<=0||x<0) return 0;
return C(x+y-1,x);
}
int main(){
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
if(k&1){
printf("%lld\n",(f(n-k/2-1,k/2+1)*f(m-k/2,k/2)%mod+f(n-k/2,k/2)*f(m-k/2-1,k/2+1)%mod)%mod);
}
else printf("%lld\n",2*f(n-k/2,k/2)*f(m-k/2,k/2)%mod);
return 0;
}