zzk的互测题真毒瘤,三道题在洛谷上都是紫题......
而且T1是NOI真题,T2是集训队真题,T3是省选真题,难度貌似是递减......
这道题是T3。
考试的时候是打表做的,30分的很显然了,n2能推出来。
f[i][j]=f[i][j-1]+f[i-1][j](i<=j),f[0][0]=1。
然后我感觉这个递推式的结构有点像杨辉三角,就打了个表。
发现f(n,m)=C(n+m,n)-C(n+m,n+1),于是就当场切掉了这道题。
当然打表找规律肯定不是正解。
正解是把这个问题转化为另一种问题。
从(0,0)走到(n+m,n-m),x坐标为'1'和'0'的和,y坐标为'1'和'0'的差。
每次只能向右上或右下走。
右上(x++,y++)就是选了'1',右下反之。
所以不考虑限制,所有情况是C(n+m,n)(n+m步里有n个选择'1'的步)。
限制是'1'>='0' , '1'-'0'>='0'-'0'
所以y>=0
也就是说,所有走到y=-1的都不合法。
而从(0,0)走到y=-1的都可以对称成从(0,-2)走到y=-1。
所以不合法方案数为C(n+m,n+1)
最终求得答案就是f(n,m)=C(n+m,n)-C(n+m,n+1)。
也有用卡特兰数的解法,我不会。
注意要用线性筛逆元求组合数(不过别的方法貌似也成)。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #define mod 20100403 5 #define ll long long 6 using namespace std; 7 8 ll n,m; 9 ll mul[2000005],inv[2000005]; 10 11 ll c(ll x,ll y) 12 { 13 return (((mul[x]*inv[x-y])%mod)*inv[y])%mod; 14 } 15 16 int main() 17 { 18 scanf("%lld%lld",&n,&m); 19 mul[0]=mul[1]=inv[0]=inv[1]=1; 20 ll tot=m+n; 21 for(ll i=2;i<=tot;i++)mul[i]=mul[i-1]*i%mod; 22 for(ll i=2;i<=tot;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod; 23 for(ll i=2;i<=tot;i++)inv[i]=inv[i]*inv[i-1]%mod; 24 ll ans=((c(tot,n)-c(tot,n+1))%mod+mod)%mod; 25 printf("%lld ",ans); 26 return 0; 27 }