Codeforces Round #791 (Div. 2) E, F 题题解 (2400,2600)
给定一个长度为 的字符串 ,由前 个小写字母和 组成。
有 次询问,给出一个前 个小写字母的子集 ,问将 中的所有 替换成 中的任意一个字符的所有方案, 包含的所有可以本质相同的回文字串的个数的和,答案对 取模。
。
随便做。
考虑回文串中的两个对称位置 ,有四种情况:
- :贡献为 。
- :贡献为 。
- :贡献为 。
- :贡献为 。
那么区间 出每个区间的贡献,每个贡献形如 ,于是高维前缀和即可。
总时间复杂度 。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1005,mod=998244353;
int n,S,q,sum[N],P[18][N],pw[N][N],zero[N][N],sta[N][N],f[1<<17][18];
char s[N],t[N];
int main(){
scanf("%d%s",&n,s+1);
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+(s[i]=='?');
for(int L=1;L<=17;++L){
P[L][0]=1;
for(int i=1;i<=n;++i)
P[L][i]=(ll)P[L][i-1]*L%mod;
}
for(int t=1;t<=n;++t)
for(int i=1;i<=n-t+1;++i){
int j=i+t-1;
zero[i][j]=zero[i+1][j-1];
pw[i][j]=pw[i+1][j-1];
sta[i][j]=sta[i+1][j-1];
if(s[i]=='?'&&s[j]=='?')++pw[i][j];
else if(s[i]!='?'&&s[j]!='?')zero[i][j]|=s[i]!=s[j];
else sta[i][j]|=(s[i]!='?'?(1<<s[i]-'a'):(1<<s[j]-'a'));
if(!zero[i][j])
for(int L=1;L<=17;++L)
(f[sta[i][j]][L]+=P[L][pw[i][j]+sum[n]-(sum[j]-sum[i-1])])%=mod;
}
for(int i=0;i<17;++i)
for(int j=0;j<1<<17;++j)if(j>>i&1)
for(int k=1;k<=17;++k)(f[j][k]+=f[j^(1<<i)][k])%=mod;
for(scanf("%d",&q);q--;){
scanf("%s",t+1),S=0;
for(int i=1;i<=strlen(t+1);++i)S|=1<<t[i]-'a';
printf("%d\n",f[S][strlen(t+1)]);
}
return 0;
}
给出正整数 ,所有不足 位(十进制)的数用前导零补充。
给出 组无序数对 ,若一个数字的相邻两位数 满足 存在于这 组数对中,则可以交换 的位置。若 可以通过若干次(包含零次)交换得到 ,则认为 和 是等价的。
求出最大整数 ,使得存在一组非负整数 满足对于任意 , 与 不等价。
更简单,不知道为何能放到 的位置,标签竟有 。
考虑 个数中形成若干等价类,要求的就是等价类的数量。对于一个等价类,考虑用其字典序最小的元素描述它。
如何保证字典序最小呢?字典序最小等价于不能再通过操作使得字典序更小,形式化地,设字典序最小的数为 ,不能找出 使得 与 都可以交换并且 。
于是可以从低位到高位状压 ,同时维护状态 ,表示能从后面移动到当前位置的数字集合,每次重新求 时间复杂度不对,那么进行预处理, 表示现在的集合为 ,在前面加入 后新的 ,然后进行 ,转移时不能使得后面能交换到当前位置的数字比当前填的数字小。
总时间复杂度 。
#include<bits/stdc++.h>
using namespace std;
const int mod=998244353;
int n,m,ans,f[50005][1024],g[1024][10],G[10][10];
int main(){
scanf("%d%d",&n,&m),f[0][0]=1;
for(int i=1,x,y;i<=m;++i)scanf("%d%d",&x,&y),G[x][y]=G[y][x]=1;
for(int s=0;s<1024;++s)
for(int i=0;i<=9;++i){
g[s][i]=1<<i;
for(int t=0;t<=9;++t)
if(G[i][t]&&(s>>t&1))
if(i<t){g[s][i]=-1;break;}
else g[s][i]|=1<<t;
}
for(int i=0;i<n;++i)
for(int s=0;s<1024;++s)if(f[i][s])
for(int j=0;j<10;++j)if(~g[s][j])
(f[i+1][g[s][j]]+=f[i][s])%=mod;
for(int s=0;s<1024;++s)(ans+=f[n][s])%=mod;
return printf("%d\n",ans),0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】