I

题意:

给出一个串,可能?、小写字母,大写字母、数字。

小写字母可以变成当前小写字母的小写或者大写形式。

数字和大写只能是当前形式。

问号可以变成另外三种形式。

现在要求相同的字符不相邻,且字符串中同时出现三种字符形式的方案数。

设dp[i][j][k],表示第i个位置为j,且当前状态为k的方案数。

k是状压的形式:[0 0 0]三个位置分别表示数字、小写和大写,其范围为[0,7]

当前的位置j通过映射,[1~62]对应[0 ~ 9, a ~ z, A ~ Z]

转移方程:

对于每个k和当前的h进行下列方程转移。

dp[i][h][st(h)|k]=j=1&&j!=h62dp[i1][j][k]

然而这样如果遇到问号,复杂度是(k=7)(j=62)(h=62)(1e5)转移,过不了。

这里考虑先对于每个k,提前把j=162dp[i1][j][k]处理好,然后对对应的h,特别的减去dp[i1][h][k],写作下式:

dp[i][h][st(h)|k]=j=162dp[i1][j][k]dp[i1][h][k]

则复杂度转化为(k=7)(j=62+h=62)(1e5)

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0),cin.tie(0)
#define int long long
const int N = 1e5+7;
int dp[2][80][10],tmp[10];
char ch[80];
map<char,int>mp;
const int mod = 998244353;
int st(int y)
{
char x=ch[y];
if(isdigit(x))
{
return 1;
}
if(islower(x))
{
return 2;
}
if(isupper(x))
{
return 4;
}
return 0;
}
signed main()
{
IOS;
int n;
cin>>n;
string s;
cin>>s;
s=' '+s;
int cnt=0;
for(int i=0;i<=9;i++)
{
ch[++cnt]=i+'0';
mp[i+'0']=cnt;
}
for(char x='a';x<='z';x++)
{
ch[++cnt]=x;
mp[x]=cnt;
}
for(char x='A';x<='Z';x++)
{
ch[++cnt]=x;
mp[x]=cnt;
}
int id=mp[s[1]];
if(st(id)==0)
{
//问号
for(int i=1;i<=62;i++)
{
dp[1][i][st(i)]=1;
}
}else if(st(id)==1)
{
//数字
dp[1][id][st(id)]=1;
}else if(st(id)==2)
{
//小写
dp[1][id][st(id)]=1;
dp[1][id+26][st(id+26)]=1;
}else if(st(id)==4)
{
//大写
dp[1][id][st(id)]=1;
}
int cur=1;
for(int i=2;i<=n;i++)
{
for(int k=1;k<=7;k++)
{
tmp[k]=0;
}
for(int j=1;j<=62;j++)
{
for(int k=1;k<=7;k++)
{
//把所有k相同的状态做前缀和转移
tmp[k]+=dp[cur][j][k];
tmp[k]%=mod;
//滚动数组清空
dp[cur^1][j][k]=0;
}
}
int now=mp[s[i]];
for(int k=1;k<=7;k++)
{
if(st(now)==0)
{
for(int id=1;id<=62;id++)
{
//问号的时候,枚举当前
dp[cur^1][id][k|st(id)]+=tmp[k]-dp[cur][id][k];
dp[cur^1][id][k|st(id)]=(dp[cur^1][id][k|st(id)]%mod+mod)%mod;
}
}else if(st(now)==1)
{
//[1,10]
int id=mp[s[i]];
dp[cur^1][id][k|st(id)]+=tmp[k]-dp[cur][id][k];
dp[cur^1][id][k|st(id)]=(dp[cur^1][id][k|st(id)]%mod+mod)%mod;
}else if(st(now)==2)
{
//小写
int id=mp[s[i]];
dp[cur^1][id][k|st(id)]+=tmp[k]-dp[cur][id][k];
dp[cur^1][id][k|st(id)]=(dp[cur^1][id][k|st(id)]%mod+mod)%mod;
id+=26;
dp[cur^1][id][k|st(id)]+=tmp[k]-dp[cur][id][k];
dp[cur^1][id][k|st(id)]=(dp[cur^1][id][k|st(id)]%mod+mod)%mod;
}else if(st(now)==4)
{
//大写
int id=mp[s[i]];
dp[cur^1][id][k|st(id)]+=tmp[k]-dp[cur][id][k];
dp[cur^1][id][k|st(id)]=(dp[cur^1][id][k|st(id)]%mod+mod)%mod;
}
}
cur=cur^1;
}
int maxn=0;
for(int i=1;i<=62;i++)
{
maxn=maxn+dp[cur][i][7];
maxn%=mod;
}
cout<<maxn<<endl;
}

本文作者:TimMCBen

本文链接:https://www.cnblogs.com/TimMCBen/p/17713224.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   TimMCBen  阅读(13)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.