Codeforces Round #791 (Div. 2) E, F 题题解 (2400,2600)

E

给定一个长度为 n 的字符串 s,由前 k 个小写字母和 ? 组成。
q 次询问,给出一个前 k 个小写字母的子集 t,问将 s 中的所有 ? 替换成 t 中的任意一个字符的所有方案,s 包含的所有可以本质相同的回文字串的个数的和,答案对 998244353 取模。
1n103,1q2105,1k17


随便做。

考虑回文串中的两个对称位置 i,j,有四种情况:

  • si=sj=?:贡献为 |t|
  • si=?,sj?:贡献为 [sjt]
  • si?,sj=?:贡献为 [sit]
  • si?,sj?:贡献为 [si=sj]

那么区间 dp 出每个区间的贡献,每个贡献形如 |t|p×[St],于是高维前缀和即可。

总时间复杂度 O(n2+217×172)

code

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

F

给出正整数 n,所有不足 n 位(十进制)的数用前导零补充。
给出 m无序数对 (ui,vi),若一个数字的相邻两位数 x,y 满足 (x,y) 存在于这 m 组数对中,则可以交换 x,y 的位置。若 A 可以通过若干次(包含零次)交换得到 B,则认为 AB 是等价的。
求出最大整数 k,使得存在一组非负整数 x1,x2,,xk(0xi<10n) 满足对于任意 1i<jkxixj 不等价。


更简单,不知道为何能放到 F 的位置,标签竟有 2600

考虑 10n 个数中形成若干等价类,要求的就是等价类的数量。对于一个等价类,考虑用其字典序最小的元素描述它。

如何保证字典序最小呢?字典序最小等价于不能再通过操作使得字典序更小,形式化地,设字典序最小的数为 d1d2dn¯10,不能找出 dj 使得 djdi,di+1,,dj1 都可以交换并且 dj<di

于是可以从低位到高位状压 dp,同时维护状态 s,表示能从后面移动到当前位置的数字集合,每次重新求 s 时间复杂度不对,那么进行预处理,gs,i 表示现在的集合为 s,在前面加入 i 后新的 s,然后进行 dp,转移时不能使得后面能交换到当前位置的数字比当前填的数字小。

总时间复杂度 O(n×210×10)

code

#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;
}
posted @   Samsara-soul  阅读(55)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示