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;
}

浙公网安备 33010602011771号