专栏文章
题解:P11487 「Cfz Round 5」Gnirts 10
P11487题解参与者 7已保存评论 6
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 6 条
- 当前快照
- 1 份
- 快照标识符
- @miqmj334
- 此快照首次捕获于
- 2025/12/04 07:14 3 个月前
- 此快照最后确认于
- 2025/12/04 07:14 3 个月前
挺好的题,来写题解了!
首先,我们可以想到,要对答案是 的 序列 计数。不妨设这样的串的数量是 ,那么答案是 。
令 为 的长度为 的前缀。
考虑对 中长度为 的前缀检查一个 串 是否合法。我们不难想到一个正确的贪心:设当前匹配到 ,设 与 匹配,那么 匹配到 往后第一个等于 的位置,没有那么整个前缀就匹配失败了。
那么我们将 划成若干个由极长的 组成的连续段(伏笔 1),不难发现这时的子序列要么在某一段内一点不取,要么就取一段前缀(其实可以合并成一种情况)。
发现若 中有 做为前缀,那么其一定是在 中插入若干个 连续段的方式生成的。怎么不重不漏的插呢?不妨对于相邻的两个字符讨论。
:只能插 。因为伏笔 1 中的连续段可以取完,然后跳过整个 段,再继续取。
:只能插 。因为是前缀嘛。
:只能插 ,原因同上。
:只能插 ,原因同上。
这个限制可以规约成:设相邻两个字符中右边的那个是 ,那么中间只能填 。
不难发现这个限制能够以一种成功的方式归约到 前面的部分与 后面的部分。(这里假设我们在算 。)
原因很简单:对于 前面的部分,肯定不能与之相同,正好符合我们的这个条件;
对于 后面的部分,其肯定不能与 相同,不然答案肯定是 或者更多。 的情况另算。
那么我们设现在有 个可以插 的空隙, 个可以插 的空隙,已经用掉 个 , 个 了。
那么答案就是 。其中 ,但是 。
直接预处理组合数然后 算出就好了。
对于 的情况:考虑 中是否有 个 与 个 ,有的话就给总答案加上 。
就做完了。
#include<bits/stdc++.h>
#define int long long
#define doub long double
#define PII pair<int,int>
#define mp make_pair
#define fir first
#define sec second
#define PC __builtin_popcountll
using namespace std;
const int maxn=6e6+7;
const int mod=2933256077;
int n,m;
bool Ss[maxn];
int Fac[maxn];
int iFac[maxn];
inline int qpow(int a,int b){
int ans=1;
while(b){
if(b&1)ans=1ull*ans*a%mod;
a=1ull*a*a%mod;
b>>=1;
}
return ans;
}
inline void Init(){
Fac[0]=1;
for(int i=1;i<=n+m+5;i++)Fac[i]=1ull*Fac[i-1]*i%mod;
iFac[n+m]=qpow(Fac[n+m],mod-2);
for(int i=n+m-1;i>=0;i--)iFac[i]=1ull*iFac[i+1]*(i+1)%mod;
}
inline int C(int n,int m){
if(n<0||m<0||n<m)return 0;
return 1ull*Fac[n]*iFac[m]%mod*iFac[n-m]%mod;
}
inline int F(int n,int m){
if(n<0||m<0)return 0;
if(n==0&&m==0)return 1;
return C(n+m-1,m-1);
}
signed main(){ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#ifndef ONLINE_JUDGE
freopen("1.in","r",stdin);
freopen("1.out","w",stdout);
#endif
cin>>n>>m;
Init();
for(int i=1;i<=n+m;i++){
char t;
cin>>t;
Ss[i]=t-'0';
}
int C0=0,C1=0;
int S0=0,S1=0;
int ans=0;
for(int i=0;i<n+m;i++){
if(i){
if(Ss[i]==0)S0++;
else S1++;
}
if(Ss[i+1]==0)C1++;
else C0++;
ans=(ans+1ull*i*F(m-S0,C0)%mod*F(n-S1,C1)%mod)%mod;
}
if(Ss[n+m]==0)S0++;
if(Ss[n+m]==1)S1++;
if((S0==m)&&(S1==n))ans+=(n+m);
ans%=mod;
cout<<ans<<endl;
return 0;
}
相关推荐
评论
共 6 条评论,欢迎与作者交流。
正在加载评论...