日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

2021牛客暑期多校训练营5 D-Double Strings(dp+组合数)

發布時間:2023/12/3 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 2021牛客暑期多校训练营5 D-Double Strings(dp+组合数) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

D-Double Strings
fi,jf_{i,j}fi,j?表示a中前i個字符,b中前j個字符相同子序列的數量,容斥轉移

fi,j=fi?1,j+fi,j?1?fi?1,j?1+{(1+fi?1,j?1)[ai=aj]}f_{i,j}=f_{i-1,j}+f_{i,j-1}-f_{i-1,j-1}+\{(1+f_{i-1,j-1})[a_i=a_j]\}fi,j?=fi?1,j?+fi,j?1??fi?1,j?1?+{(1+fi?1,j?1?)[ai?=aj?]}

gi,jg_{i,j}gi,j?表示a中前i個字符,b中前j個字符滿足小于關系子序列的數量

類似相同子序列數量轉移即可。
gi,j=gi?1,j+gi,j?1?gi?1,j?1+(1+gi?1,j?1)+{(fi?1,j?1+1)[ai<aj]}g_{i,j}=g_{i-1,j}+g_{i,j-1}-g_{i-1,j-1}+(1+g_{i-1,j-1})+\{(f_{i-1,j-1}+1)[a_i<a_j]\}gi,j?=gi?1,j?+gi,j?1??gi?1,j?1?+(1+gi?1,j?1?)+{(fi?1,j?1?+1)[ai?<aj?]}

Code1

#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=5010; const ll mod=1000000007; char a[N],b[N]; int f[N][N],g[N][N]; int n,m; int main() {scanf("%s%s",a+1,b+1);n=strlen(a+1);m=strlen(b+1);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(a[i]==b[j])f[i][j]=(1ll*f[i-1][j]+f[i][j-1]+1)%mod;elsef[i][j]=(1ll*mod+f[i-1][j]+f[i][j-1]-f[i-1][j-1])%mod;}for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(a[i]<b[j]) g[i][j]=(1ll*g[i-1][j]+g[i][j-1]+1+f[i-1][j-1])%mod;elseg[i][j]=(1ll*g[i-1][j]+g[i][j-1])%mod;}printf("%lld\n",g[n][m]); }

Code2

首先求出相同子序列,然后枚舉哪個位置不同,即第一個ai<aja_i<a_jai?<aj?,然后利用下面公式加快計算。

∑0≤i≤k(ni)(mk?i)=(n+mk)\sum_{0\leq i\leq k}\dbinom{n}{i}\dbinom{m}{k-i}=\dbinom{n+m}{k}0ik?(in?)(k?im?)=(kn+m?)

于是有
∑0≤i≤m(ni)(mi)∑0≤i≤m(ni)(mm?i)=(n+mm)\sum_{0\leq i\leq m}\dbinom{n}{i}\dbinom{m}{i}\sum_{0\leq i\leq m}\dbinom{n}{i}\dbinom{m}{m-i}=\dbinom{n+m}{m}0im?(in?)(im?)0im?(in?)(m?im?)=(mn+m?)

#include<bits/stdc++.h> using namespace std; using ll=long long; template <class T=int> T rd() {T res=0;T fg=1;char ch=getchar();while(!isdigit(ch)) {if(ch=='-') fg=-1;ch=getchar();}while( isdigit(ch)) res=(res<<1)+(res<<3)+(ch^48),ch=getchar();return res*fg; } const int N=5010; const int mod=1000000007; char a[N],b[N]; int f[N][N]; int n,m; int fac[N<<1],inv[N<<1]; ll qmi(ll a,ll b){ll v=1;while(b){if(b&1) v=v*a%mod;a=a*a%mod;b>>=1;}return v;} void init() {fac[0]=1;for(int i=1;i<=10000;i++) fac[i]=1ll*fac[i-1]*i%mod;inv[10000]=qmi(fac[10000],mod-2);for(int i=9999;i>=0;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod; } int C(int n,int m){return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;} int main() {init();scanf("%s%s",a+1,b+1);n=strlen(a+1);m=strlen(b+1);for(int i=1;i<=n;i++)for(int j=1;j<=m;j++){if(a[i]==b[j])f[i][j]=(1ll*f[i-1][j]+f[i][j-1]+1)%mod;elsef[i][j]=(1ll*mod+f[i-1][j]+f[i][j-1]-f[i-1][j-1])%mod;}ll ans=0;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)if(a[i]<b[j])ans=(ans+1ll*(f[i-1][j-1]+1)*C(n-i+m-j,n-i)%mod)%mod;printf("%lld\n",ans); }

總結

以上是生活随笔為你收集整理的2021牛客暑期多校训练营5 D-Double Strings(dp+组合数)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。