关于快速幂的运用G - Maximum Palindromes HackerRank - maximum-palindromes

一道关于快速幂的题目,没做过几道这种题目,本人原来没能做出来,现在写出来自己现在看这道题的一些体会
G - Maximum Palindromes
Madam Hannah Otto, the CEO of Reviver Corp., is fond of palindromes, or words that read the same forwards or backwards. She thinks palindromic brand names are appealing to millennials.
As part of the marketing campaign for the company’s new juicer called the Rotator™, Hannah decided to push the marketing team’s palindrome-searching skills to a new level with a new challenge.
In this challenge, Hannah provides a string s consisting of lowercase English letters. Every day, for q days, she would select two integers l and r , take the substring sl…r,(the substring of s from index l to index r ), and ask the following question:Consider all the palindromes that can be constructed from some of the letters from sl…r. You can reorder the letters as you need. Some of these palindromes have the maximum length among all these palindromes. How many maximum-length palindromes are there?
For example, if s=madamimadam,l=4,and r=7, then we have,
在这里插入图片描述
Your job as the head of the marketing team is to answer all the queries. Since the answers can be very large, you are only required to find the answer mod 1e9+7.
Sample Input 0
week
2
1 4
2 3
sample Output 0
2
1
题目大体的意思是:给你个字符串,再给个区间,l,r。让你求l,r之间内,能形成的最大回文子串的种类数(不是长度)。
结题思路:
(1)就是排列组合的思路,先把阶乘打表,然后再把l,r 之内的每个字母的数量统计出来,用的是sum[i][j], i 代表字符串的长度,j代表字母0-26
(2)然后将区间内的字母给搞出来num[i]=sum[r] [i]=sum[l-1][i].然后统计成对的个数和单个的个数。
(3)排列组合公式:= 总字母的对数的阶乘 / 每个字母对数的阶乘。(这个可以举例出来,初中的排列组合问题)
例如ammabbcc.很明显有三对字母。答案就是amc的排列,而每个字母只有一对.
下面直接给出代码,解释也在下面

 #include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
const int maxn=1e6+10;
void acc_ios()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
}
string s;
int sum[maxn][26];
int num[30];
int fac[maxn];
int fast_pow(int a,int b)//快速幂
{
    int ans = 1;
    while(b)
    {
        if(b&1)
            ans = (ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
signed main()
{
    acc_ios();
    cin>>s;
    fac[0]=1;
    for(int i=1; i<maxn; i++)
    {
        fac[i]=(fac[i-1]*i)%mod;
    }
    for(int i=0; i<s.size(); i++)
    {
        int w= s[i] -'a';
        sum[i+1][w]=1;
        for(int j=0; j<26; j++)
        {
            sum[i+1][j]+=sum[i][j];
        }
    }
    int q;
    cin>>q;
    while(q--)
    {
        int l,r;
        cin>>l>>r;
        for(int i=0; i<26; i++)
        {
            num[i] = sum[r][i]-sum[l-1][i];
        }
        int od=0,ev=0;
        int ano=1;
        for(int i=0; i<26; i++)
        {
            ev+=num[i]/2;//统计对数
            od+=num[i]&1;//统计了单个数目
            if(num[i]/2>1)
                ano=(ano*fac[num[i]/2]%mod)%mod;//对数连续阶乘
            ano%=mod;
        }
        ano=fast_pow(ano,mod-2);//求逆元(现在只知道除的数字太大的时候要成乘以逆元)还没搞懂。。。
        if(!od )
            od=1;
        cout<<(((fac[ev]*ano)%mod)*od%mod)%mod<<endl;//最终的公式:单个的数目*总对数的个数的阶乘/每个字母对数的阶乘。
    }
    return 0;
}
 
 


     
                    
                      
           
 

现在的我还是个菜鸡儿,很多地方还没搞懂,搞懂了会继续写下去,包括细节的地方和原理。

发布了9 篇原创文章 · 获赞 0 · 访问量 168

猜你喜欢

转载自blog.csdn.net/luoxutimberjack/article/details/104329840