[SCOI2010] 生成字符串

zzk的互测题真毒瘤,三道题在洛谷上都是紫题......

而且T1是NOI真题,T2是集训队真题,T3是省选真题,难度貌似是递减......

这道题是T3。

洛谷 P1641 传送门

考试的时候是打表做的,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\n",ans);
26     return 0;
27 }

 

posted @ 2018-10-04 19:28  cervusky  阅读(167)  评论(0编辑  收藏  举报

Contact with me