洛谷 P11487 「Cfz Round 5」Gnirts 10——题解
洛谷P11487「Cfz Round 5」Gnirts 10
摸鱼环节
「Cfz Round 5」Gnirts 10
题目背景
English statement. You must submit your code at the Chinese version of the statement.
In Memory of \(\text{F}\rule{66.8px}{6.8px}\).
题目描述
题面还是简单一点好。
- 给定 \(n, m\),以及一个长为 \(n + m\) 的 \(\tt{01}\) 串 \(S\)。
- 对于 \(\tt 01\) 串 \(T\),定义 \(f(T)\) 为 \(S\) 的最长的前缀的长度,使得该前缀是 \(T\) 的子序列 \(^\dagger\)。
- 对于每个 恰包含 \(\bm n\) 个 \(\tt 1\) 和 \(\bm m\) 个 \(\tt 0\) 的 \(\tt{01}\) 串 \(T\),求 \(f(T)\) 的和。答案对 \(2933256077^\ddagger\) 取模。
\(\dagger\):请注意,子序列可以不连续。换句话说,\(a\) 是 \(b\) 的子序列,当且仅当在 \(b\) 中删去 \(\geq 0\) 个字符后,可以得到 \(a\)。注意,空串总是任何串的子序列。
\(\ddagger\):模数为质数。
输入格式
第一行包含两个整数 \(n, m\)。
第二行包含一个长度为 \(n + m\) 的 \(\tt 01\) 串 \(S\)。
输出格式
输出一行一个整数,表示答案对 \(2933256077\) 取模后的结果。
样例 #1
样例输入 #1
2 1
000
样例输出 #1
3
样例 #2
样例输入 #2
5 5
0010111011
样例输出 #2
1391
提示
「样例解释 #1」
所有可能的序列有且仅有公共序列 \(\texttt{0}\)。因为恰有 \(3\) 种不同的 \(T\)(\(\tt 110, 101, 011\)),所以答案为 \(1\times 3 = 3\)。
「数据范围」
对于所有测试数据,保证 \(1 \leq n, m \leq 3\times 10^6\)。
本题采用捆绑测试。
- Subtask 0(13 points):\(\max(n, m) \leq 5\)。
- Subtask 1(13 points):\(\max(n, m) \leq 100\)。
- Subtask 2(34 points):\(\max(n, m) \leq 3 \times 10^3\)。
- Subtask 3(40 points):无特殊限制。
大数学。
正片开始
考虑到我们只关心答案,而答案只需要 \(S\) 某种前缀的个数,并不需要考虑具体的方案,于是我们可以从前缀的方向考虑。
对于答案而言,首先答案对质数取模,其次每个合法的\(T\),可以看作是 \(n\) 个 \(1\) 和 \(m\) 个 \(0\) 的一种组合。于是得到暴力枚举每种组合计算答案的朴素算法,很显然,这只能搞到13分。
考虑对 \(S\) 的前缀一位位处理答案,对于一个 \(S\) 的前缀 \(k\) ,长度为 \(l\) ,其中有 \(cnt0\) 个 \(0\) , \(cnt1\) 个 \(1\) 。
假设第 \(l+1\) 位为 \(1\) ,那显然,剩下的 \(n-cnt1\) 个 \(1\) 只能插在第 \(l\) 位之前,不然会导致前缀变长。
也就是要把 \(n-cnt1\)个\(1\) 分散在 \(cnt0\) 个 \(0\) 之间,两个 \(0\) 之间可以没有1。
于是插入\(1\)的答案为 \(\dbinom{n-cnt1+cnt0-1}{cnt0-1}\) 同理, \(0\) 则是有 \(cnt1\) 块板,于是 \(0\) 的答案 \(\dbinom{m-cnt0+cnt1}{cnt1}\)。
一位的答案为:
$ans=\sum_{i=1}^{n+m} i\times g(i) $。
完整代码
#ifdef ONLINE_JUDGE
#else
#define Qiu_Cheng
#endif
#include <bits/stdc++.h>
#define int long long
using namespace std;
// typedef long long ll;
const int N=6e6+50,M=1e6,mod=2933256077;
int fac[N],ifac[N],inv[N];
int C(int a,int b)
{
if(a==b) return 1;
if(a<b||b<0) return 0;
return fac[a]*ifac[a-b]%mod*ifac[b]%mod;
}
void YCL()
{
fac[0]=1;inv[1]=1;ifac[0]=1;
for(int i=1;i<=6e6;i++)
{
fac[i]=fac[i-1]*i%mod;
if(i>=2)inv[i]=(mod-mod/i)*inv[mod%i]%mod;
ifac[i]=ifac[i-1]*inv[i]%mod;
}
}
int n,m,len,ans=0;
string s;
inline void solve()
{
YCL();
cin>>n>>m;len=n+m;
cin>>s;s=' '+s;
int cnt0=0,cnt1=0;
for(int i=1;i<=len;i++)
{
if(s[i]=='0')cnt0++;
else cnt1++;
ans=(ans+i*(s[i+1]=='0'?C(m-cnt0+cnt1-1,cnt1-1)*C(n-cnt1+cnt0,cnt0)%mod:C(n-cnt1+cnt0-1,cnt0-1)*C(m-cnt0+cnt1,cnt1)%mod))%mod;
}
cout<<ans<<endl;
}
signed main()
{
#ifdef Qiu_Cheng
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
// int QwQ;
// cin>>QwQ;
// while(QwQ--)solve();
solve();
return 0;
}
// 6666 66666 666666
// 6 6 6 6 6
// 6 6 6666 6
// 6 6 6 6 6
// 6666 6 6 6666666
//g++ -O2 -std=c++14 -Wall "-Wl,--stack= 536870912 " cao.cpp -o cao.exe
完结收工!!!!!
看完点赞,养成习惯
\(\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\Downarrow\)