1. 程式人生 > >[SCOI2010] 生成字符串

[SCOI2010] 生成字符串

cst () pan algo cor std str define namespace

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

而且T1是集訓隊真題,T2是NOI真題,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 }

[SCOI2010] 生成字符串