Google Kickstart2021 Round C Problem A

数位DP
传送

思路

简单的数位DP,假定每一位的字符前面是最大的字符,对于每一位的字符,小于当前字符的数量是(s[i]-'a'),此时如果这样选择,那么后面的每一个到字符串中间的字符都可以任选m个,设第i个到中间字符的数量是y,所以此时可以构成的满足条件的字符是\((s[i]-'a')*m^y\)

但是我们忽略了一种情况,如果全选最大的字符,会不会超出字典序,这种情况需要特判

举个例子理解

bcdabc

构造时
第一个可以选择a,b
那么由a为开头的字符串就可以构造\(m^y\)个(此时一定保证字典序小于字符串)
选择b开头时,那么第二个可以选择a,b,c,选择a,b时可以构造\(m^(y-1)\)

选择b开头,c为第二个时,又需要像刚刚那样考虑,

最后我们需要考虑b,c,d作为的回文串的一半是否满足小于字典序,决定是否++

你可以画一棵树出来考虑

CODE

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10,mod=1e9+7;
#define ll long long 
int n,m;
ll p[maxn];
int t;
int id=0;
int main(){
    cin>>t;
    
    while(t--){
        cin>>n>>m; 
        string s;cin>>s;
        p[0]=1;
        for(int i=1;i<=n;++i) p[i]=((ll)p[i-1]%mod*m%mod)%mod;//预处理m的次方
        ll res=0;
        int mid=(n+1)/2;
        for(int i=0;i<mid;++i){
            res=(res%mod+(ll)(s[i]-'a')*(p[mid-i-1])%mod)%mod;//对于每一位一定满足条件的方案数
            res%=mod;
        }
        int t=0;//判断由最后一位构成的字符串是否满足条件(字典序小于给定的字符串)
        for(int i=mid-1,j=n-i-1;i>=0;++j,--i){
            if(s[i]!=s[j]){
                if(s[i]<s[j]){
                    t=1;
                }
            }break;
        }
        res=(res+t)%mod;
        cout<<"Case #"<<++id<<": "<<res<<endl;
    }return 0;
    
}

posted @ 2024-12-22 12:46  归游  阅读(9)  评论(0)    收藏  举报