【比赛小结和题解】Codeforces Global Round 1 注意贪心,简单dp技巧,还有AC自动机+数位dp

本文是关于Codeforces Global Round 1的比赛总结,详细解析了数位dp、AC自动机在1110H - Modest Substrings题目中的应用,以及贪心策略在1110G - Tree-Tac-Toe题目中的关键作用。同时,作者分享了在1110F - Nearest Leaf和1110E - Magic Stones题目中采用离线处理和差分序列判断的方法。文章强调了仔细阅读题目和代码的重要性,以及在编程竞赛中不断学习和总结经验的必要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

从重要的题开始
题解连接

1110H - Modest Substrings

题意:
求长度为n的字符串,最多有多少个子串x,满足L<=x<=R, |L|<=|R|<= 800 , n <= 2000 , 都是10进制表示

这是一道数位dp好题!感谢fdf大佬的指教。fdf的题解
我们把所有子串的贡献放在它第一次脱离限制的地方统计。而脱离限制可以枚举l或者r的前缀再枚举下一维统计。这里我们需要固定该串的长度,因为脱离限制后任意填,只要长度合法即可
如果[l] < |r| - 1,还需要统计长度介于两者之间的串。
把所有脱离限制的串插入AC自动机(记录每个状态所有脱离限制的合法长度),则只要匹配到该节点,并且长度合法即可贡献答案。并且所有fail树的祖先作为该状态的后缀也可以贡献答案。
f(i,u)表示长度为i,匹配到AC自动机上u,的最优答案。转移的时候预处理g(x,i)表示节点x,还剩长度i可以贡献的答案数。
因为要求字典序最小,所以记忆化搜索,逐位确定最优解
代码分类讨论写得很长,但是注释还是比较清晰的

总结:
L == R的特判打错了,调了1个小时。这样的错误真的必须仔仔细细的把每个代码的细节看清楚,不能借助对拍!
为什么还是对拍出错就知道哪里错了,而自己看代码却查不出来。必须改正自己调题的恶习,必须静心把每个地方的错误看出来!代码真的要一句一句读!
刻骨铭心的教训啊!

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,char> pr;

const ll inf = 2e18;
const int N = 2e4 + 10;
const int maxn = 2020;
const ll mod = 1e9 + 7;

char s1[maxn],s2[maxn];
int a[maxn],b[maxn];
int lenl,lenr,n;
int f[maxn][N],nxt[N][10],fail[N],g[N][maxn],trans[N][10],tot;

void init(){
   
	int cur = 0;
	rep(i,1,lenl) a[i] = s1[i] - '0';
	rep(i,1,lenr) b[i] = s2[i] - '0';
	if ( lenl < lenr ){
    //上、下界长度不同分开考虑
		cur = 0;
		rep(i,1,lenl){
   
			rep(j,a[i] + 1,9){
    //枚举脱离限制的地方。自由节点固定长度。每个子串在刚好脱离限制的时候统计答案、因为只要长度够一定贡献
				if ( !nxt[cur][j] ) nxt[cur][j] = ++tot;
				int x = nxt[cur][j];
				g[x][lenl - i]++;
			}
			if ( !nxt[cur][a[i]] ) nxt[cur][a[i]] = ++tot;
			cur = nxt[cur][a[i]];
		}	
		g[cur][0]++;//刚好顶满下界也合法
		
		cur = 0;
		rep(i,1,lenr){
   
			rep(j,0,b[i] - 1)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值