题解:P11655 「FAOI-R5」Lovely 139

题解:P11655 「FAOI-R5」Lovely 139

题目传送门

前置知识

题目思路

对于一个 \(\tt 01\)\(S\)(下标从 \(1\) 开始),我们定义它的一个区间 \([l,r]\)极长颜色段,当且仅当它同时满足以下条件:

  • 如果 \(l\neq 1\)\(S_{l-1}\neq S_l\)
  • 如果 \(r\neq \lvert S\rvert\)\(S_{r+1}\neq S_r\)
  • \(\forall i\in[l,r),S_i=S_{i+1}\)

观察上述条件,不难发现一个性质,即对于一个字符串 \(S\),两个相邻的字符不同的数量加上 \(1\) 就是 \(S\) 的不同极长颜色段数。即:

\[g(s)=(\sum_{i=1}^n i(S_i \neq S_{i+1}))+1 \]

所以,问题就分为了两个部分:

  • 计算所有满足条件的相邻两个字符之和
  • 以及这些字符串的总数。(即通过排列组合生成的所有字符串所加的 \(1\) 之和)

计算字符串的总数

显然,这是一个排列组合问题,结果即为 \(C_{m+n}^n\)\(C_{m+n}^m\),实际上两者的结果都是一样的,读者可以自己赋特殊值进行证明。所以通过排列组合生成的所有字符串所加的 \(1\) 之和也就是 \(C_{m+n}^n\)\(C_{m+n}^m\) 了。

计算所有满足条件的相邻两个字符之和

对于每一组 \(S_i,S_{i+1}(S_i \neq S_{i+1})\),则还有 \(n-1\)\(0\)\(m-1\)\(1\)\(n+m-2\)\(0\)\(1\)。则对于其他子串的排列方案为 \(C_{m+n-2}^{n-1}\)\(C_{m+n-2}^{m-1}\)。同理,两者结果仍相同。又因为对于每一组 \(S_i,S_{i+1}(S_i \neq S_{i+1})\),有 \(\tt 01\)\(\tt 10\) 两种情况,并且 \(S\) 中有 \(n+m-1\) 组这样的数,所以所有满足条件的相邻两个字符之和为:

\[2 \times (n-m+1) \times C_{m+n-2}^{n-1} \]

所以:

\[f(n,m)=2 \times (n-m+1) \times C_{m+n-2}^{n-1}+C_{m+n}^n \]

代码实现

0pts Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1e9+7;
ll jc(ll a){
	ll sum=1;
	for(int i=1;i<=a;i++){
		sum=sum*i;
	}
	return sum;
}

ll zh(ll a,ll b){return jc(b)/(jc(a)*jc(b-a));}

int main(){
	ll T,n,m;
	cin>>T;
	while(T--){
		cin>>n>>m;
		cout<<(zh(n,n+m)+2*(n+m-1)*zh(n-1,n+m-2))%mod<<"\n";
	}
	return 0;
}

一开始推得规律后,就直接写了个阶乘和组合函数,但显然不行,还要处理对 \(10^{9}+7\) 取模的问题。再到后来甚至想使用高精乘,但仍无法处理对 \(10^{9}+7\) 取模的问题。
于是想到了P3811 【模板】模意义下的乘法逆元B3717 组合数问题,知道是乘法逆元,于是套上了板子。

AC Code

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const ll mod=1e9+7;
const ll MAXN=2e6+10;
ll f[MAXN],inv[MAXN];

inline ll read() { 
    ll x = 0, f = 1; char ch = getchar();
    while(ch>'9'||ch<'0') { if(ch=='-') f=-f;ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=x*10+ch-'0';ch=getchar(); }
    return x*f;
}
ll zh(ll n,ll m){
	return f[n]*inv[m]%mod*inv[n-m]%mod;
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	ll T,n,m;
	T=read();
	f[1]=f[0]=inv[1]=inv[0]=1;
	for(ll i=2;i<=MAXN;i++){
      f[i]=f[i-1]*i%mod;
      inv[i]=(mod-mod/i)*inv[mod%i]%mod;
  } 
	for(ll i=1;i<=MAXN;i++)  inv[i]=inv[i-1]*inv[i]%mod;
	for(ll i=1;i<=T;i++){
		n=read(),m=read();
		if(n==0&&m==0) cout<<1<<"\n";
		else if(n==0||m==0) cout<<1<<"\n";
		else{
			cout<<((n+m-1)*2*(zh(n+m-2,n-1)%mod)%mod+(zh(n+m,n)%mod))%mod<<"\n";
		}
	} 
	return 0;
}
posted @ 2025-02-03 16:23  M1_Byte  阅读(17)  评论(0)    收藏  举报