题解: Moo Decomposition G

绿题秒了。

真不知道这个 \(L\) 有什么用

由题可知,一个合法子序列是\(MOOO\dots OO\),只有 \(1\) 个 \(M\),所以 \(M\) 非常重要。

先看一组样例:

\[MOOMOO \]

第一个 \(M\) 不能选后面的2个 \(O\) ,为什么?因为后面的2个 \(O\) 必须被第二个 \(M\) 选。

从这个样例就能看出来,第一个 \(M\) 能选的 \(O\) 实际上只有2个。

所以后面的 \(M\) 能对前面的 \(M\) 造成约束,后面选过的前面不能再选。

使用类似于 DP 的思路,不难想到从后往前枚举:

设\(sheng\) 表示当前位置后面剩余0的数量。

  • 每遇到一个 \(O\) ,\(sheng++\)。
  • 每遇到一个 \(M\),就要使 \(ans\) 乘上 \(C_{sheng}^K\) ,同时\(sheng\) 要减去 \(K\) 。
  • 如果此时 \(sheng<0\),那么说明 \(O\) 不够用,直接输出0并结束程序。

对于 \(L\) ,考虑子序列是否会跨越循环节进行匹配。

这显然是不可能的,因为如果当前段的 \(M\) 匹配上后面的一个 \(O\) ,那么当前段就一定会剩余 \(O\) ,也就不合法了。

所以,每个循环节是不会相互影响的,答案就是 \(ans^L\) 了。

代码如下:

// Problem: P12028 [USACO25OPEN] Moo Decomposition G
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P12028
// Author: hemingxi_2030
// Memory Limit: 256 MB
// Time Limit: 2000 ms
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
#define int long long
#define qy(FILE) freopen(FILE".in","r",stdin);freopen(FILE".out","w",stdout);
using namespace std;
const int N=1e6+5,INF=0x3f3f3f3f3f3f3f3f,mod=1e9+7;
int power(int a,int b)
{
	int res=1;
	a=a%mod;
	while(b)
	{
		if(b&1) res=res*a%mod;
		a=a*a%mod;
		b/=2;
	}
	return res%mod;
}
int jie[N],jie_ni[N];
void init()
{
	jie[0]=1;
	for(int i=1;i<=N-5;i++)
		jie[i]=jie[i-1]*i%mod;
	jie_ni[N-5]=power(jie[N-5],mod-2);
	for(int i=N-5;i>0;i--)
		jie_ni[i-1]=jie_ni[i]*i%mod; 
}
int C(int x,int y)
{
	if(x<y||y<0||y<0)return 0;
	return jie[x]*jie_ni[y]%mod*jie_ni[x-y]%mod;
}
int k,n,l,ans=1;
string s;
signed main()
{
//	qy("q");
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	init();
	cin>>k>>n>>l;
	cin>>s;
	s=' '+s;
	int sheng=0;
	for(int i=n;i>=1;i--)
	{
		if(s[i]=='O') sheng++;
		else
		{
			ans=(ans*C(sheng,k))%mod;
			sheng-=k;
			if(sheng<0)
			{
				cout<<0<<' ';
				return 0;
			}
		}
	}
	cout<<power(ans,l)<<'\n';
	return 0;
}

posted on 2026-10-20 07:59  hemingxi_2030  阅读(4)  评论(0)    收藏  举报