洛谷 P5684 讲解(C++)

传送门

目录

思路:

代码:


思路:

        这道题让我们求非回文串的个数,但很不好求。所以,我们可以先求出回文串个数,再用总

排列个数减去回文串个数,就能得到非回文串个数。

        总排列个数很容易求,即 n * (n - 1) * (n - 2) * ...... * 2 * 1。所以,这道题难点就在于如何求回

文串个数。

        如果一个字符串是回文串。那么,它的左边也就等于它的右边。我们只需要求出一边的组合

个数,即 (n / 2) * (n / 2 - 1) * ...... * 2 * 1。就是回文串排列个数。

        但是,如果有字母相等,又该怎么解决?

        如果有字母相等,我们应求出其排列个数 (设其为 num) ,即 num * (num - 1) * ...... * 2 * 1。

但是,有可能会重复。举个例子:

        假如有 4 个字母 b 。求出组合个数自然没有问题。但是,在之前,我们已经求出回文串组合

个数,就会出现被重复计算。所以,我们需要去除被重复计算部分,即出去 (num / 2) * (num / 2

- 1) * ...... * 2 * 1。读者可以自行思考为什么要出去这些数。 

         最后,在计算重复字母时,我们只需要计算 num * (num - 1) * ...... *(num / 2 + 2) *(num / 2 + 1)。

代码:

#include<bits/stdc++.h>
using namespace std;
long long lis[29]; //桶,记录字母出现个数 
const long long maxn=1e9+7; //取模数字: 
int main(){
	long long n,ans=1;
	char c;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>c;
		lis[c-'a']++; //增加该字母个数 
	}
	int ji=0,xb=0;
	for(int j=0;j<26;j++) ji+=lis[j]%2; //计算出现奇数个字母个数 
	for(int i=2;i<=n;i++) ans=(ans*i)%maxn; //计算总排列个数 
	if(ji>1){ //如果奇数个字母个数超过一个,没有回文串,直接输出 
		cout<<ans;
		return 0;
	}
	long long num=1;
	for(int i=1;i<=n/2;i++) num=(num*i)%maxn; //计算回文串排列个数 
	for(int i=0;i<26;i++){ 
		//计算字母相等个数 
		for(int j=lis[i]/2+1;j<=lis[i];j++) num=(num*j)%maxn;
	}
	ans=(ans-num+maxn)%maxn; //得到答案(ans-num可能为负数) 
	cout<<ans;
	return 0;
} 

  谢谢大家的阅读!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值