首页 > 其他分享 >[CSP-S 2023] 消消乐

[CSP-S 2023] 消消乐

时间:2023-12-13 17:57:19浏览次数:31  
标签:cnt last ll 消消 ull 2023 CSP dp define

赛时

想到了一个规律,当一个字符串的头和首相等,并且中间的字符串同样可以被消除的话,那么这个大字串也就可以被消除。

虽然竭尽全力想到了这一点,不过还不知道如何实现,开始的想法是:

先使用 \(vector\) 来记录每一个字母所在的分别的下标,然后先从两个相邻字母的开始找(因为这样必定是可以消掉的),然后通过这个字串开始往两边遍历,一直找到找不下去为止。

然而,这样的想法是大错特错的,因为有 \(CBBAAC\) 这样的情况,按照我的思想是无法找到的,在考试中想到了 区间dp,同样的在考试中也想到了 来找到一段回文字符串的方法,只是没有想到使用 可以得到 \(50pts\) 的好成绩,思路还是很简单的:

每次枚举一个端点 \(l\) ,然后对这个 \([l, n]\) 的字串进行括号匹配,这时候就可以累加可以匹配的字符串,就可以完成。

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rint register int
#define For(i, j, k) for(rint i = j; i <= k; i++)
using namespace std;

inline int read(){
  int f = 1,x = 0;
  char ch = getchar();
  while(!isdigit(ch)){
	if(ch == '-')f = -1;
  	ch = getchar();
  }
  while(isdigit(ch)){
  	x = (x << 1) + (x << 3) + (ch ^ 48);
  	ch = getchar();
  }
  return x * f;
}
inline void print(int x){
  if(x > 9)print(x / 10);
  putchar(x % 10 + '0');
}

string a;

ll ans = 0;
const int ull base = 1e7 + 7;
ull H[2000010];

signed main(){
	int n = read(); cin >> a;
	a = ' ' + a; H[0] = 1;
	For(i, 1, n){
		H[i] = H[i - 1] * base;
	}
	For(i, 1, n){
		stack<char> s; 
		ull cnt = 0;
		For(j, i, n){
			if(!s.empty() && s.top() == a[j])
				cnt -= s.top() * H[s.size()], s.pop();
			else s.push(a[j]), cnt += s.top() * H[s.size()]; 
			if(cnt == 0)
				ans++;
		}
	} 
	cout << ans; 
  return 0;
}

- Solve 1

果然正解其实就藏在骗分之中。

Hash + 栈

使用 Hash 处理现在枚举过的无法匹配的未匹配的字串的值,如 \(ABBA\) 假设我们处理到了 \(i = 3\) 那么剩下没有匹配的就会是 \(A\) ,这样我们就可以开始找到另一个 \(Hash\) 值表示 \(A\) 的字符串,因为 \(Hash\) 值是单调递增的(不考虑取模),所以如果之前有一个 \(Hash\) 值与现在的相等,那么说明,中间的这一段字符串一定就可以被消除。

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rint register int
#define For(i, j, k) for(rint i = j; i <= k; i++)
using namespace std;

inline int read(){
  int f = 1,x = 0;
  char ch = getchar();
  while(!isdigit(ch)){
	if(ch == '-')f = -1;
  	ch = getchar();
  }
  while(isdigit(ch)){
  	x = (x << 1) + (x << 3) + (ch ^ 48);
  	ch = getchar();
  }
  return x * f;
}
inline void print(int x){
  if(x > 9)print(x / 10);
  putchar(x % 10 + '0');
}

string a;
stack<char> s; 
ull cnt = 0;
const ull base = 1e9 + 7;
ull H[2000010];
ll ans = 0;
unordered_map<ull, ll> sum;

signed main(){
	int n = read(); cin >> a;
	a = ' ' + a;
	H[0] = 1;
	For(i, 1, n){
		H[i] = H[i - 1] * base;
	}
	sum[0] = 1;
	For(i, 1, n){
		if(!s.empty() && s.top() == a[i])
			cnt -= s.top() * H[s.size()], s.pop();
		else
			s.push(a[i]), cnt += a[i] * H[s.size()]; 
		ans += sum[cnt];
		sum[cnt]++;
	}
	cout << ans;
  return 0;
}

- Solve 2

这就与赛时想法比较像了。

运用结论,设 \(dp_i\) 表示以 \(i\) 为结尾的匹配字符串的个数。

那么肯定有以下的结论,令 \(last_i\) 表示与 \(a_i = a_{last_i}\) 的且 \([last_i, i]\) 可以被消除的最近的下标, \(dp_i\) 的改变一定是 \(dp_{last_i - 1} + 1\) ,如何去找到这个 \(last_i\) 呢?通过之前的思想,我们可以把大事化小,通过跳来解决 \(last_i \Leftarrow last_{last_i - 1} \dots\) 原理是什么呢,其实就是一直找回文字符串。

代码如下

#include <bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define rint register int
#define For(i, j, k) for(rint i = j; i <= k; i++)
#define down(i, j, k) for(rint i = k; i <= j; --i)
using namespace std;

inline int read(){
  int f = 1,x = 0;
  char ch = getchar();
  while(!isdigit(ch)){
	if(ch == '-')f = -1;
  	ch = getchar();
  }
  while(isdigit(ch)){
  	x = (x << 1) + (x << 3) + (ch ^ 48);
  	ch = getchar();
  }
  return x * f;
}
inline void print(int x){
  if(x > 9)print(x / 10);
  putchar(x % 10 + '0');
}

ll to[2000010], dp[2000010], ans;

signed main(){
	int n = read();
	string a;
	cin >> a;
	a = ' ' + a;
	For(i, 1, n){
		for(int j = i - 1; j > 0; j = to[j] - 1){
			if(a[j] == a[i]){
				to[i] = j;break;
			}
		}
		if(to[i])dp[i] = dp[to[i] - 1] + 1, ans += dp[i];
	} 
	cout << ans;
  return 0;
}

标签:cnt,last,ll,消消,ull,2023,CSP,dp,define
From: https://www.cnblogs.com/lightstarup/p/17899610.html

相关文章

  • 2023-12-13:用go语言,密码是一串长度为n的小写字母,一则关于密码的线索纸条, 首先将字母a
    2023-12-13:用go语言,密码是一串长度为n的小写字母,一则关于密码的线索纸条,首先将字母a到z编号为0到25编号,纸条上共有n个整数ai,其中a1表示密码里第一个字母的编号,若i>1的话就表示第i个字母和第i-1个字母编号的差值,例如,a2就代表密码中第1个字母和第2个字母编号的差值,若密码是acb,......
  • [CSP-S 2023] 密码锁
    [CSP-S2023]密码锁考场上我跟个\(somebody\)一样,一看就想:一眼乘法原理,乱搞写一下就出来了。当时我还算了一下暴力好像也不会超时,结果,每天在yz日以继日的颓废考试经验,我断定CSP-S是不会考这么\(!\)复杂的题目的,结果暴力出奇迹,就是枚举模拟。考试后,一看wc枚举,我断定我......
  • 2023.12.13日报
    最近事情比较多,写日报也有点怠惰了,主要是偶尔会忘记,简单总结一下这两天的工作首先是使用jfinal做大作业,实话说这玩意一开始我觉得并不好用,因为页面也很简陋,后端也有点看不懂但是在实际体验并且调用百度翻译和图像处理的api后,感觉用起来还可以,其实和springboot有点类似现在是已......
  • Solution Set 2023.12.13
    CF1736ESwapandTake设在第\(i\)次操作后产生贡献的值为初始序列的\(a_{p_i}\),可以发现产生的贡献的指针移动方式为每次向后移动\(1\),而通过交换数字最多可以使得某个数字每次向后移动\(1\),由此可以得出每次产生贡献的位置单调不减,即\(p_1\lep_2\le\cdots\lep_n\)......
  • 【2023-12-12】家庭分工
    20:00人们说得好,在耕种多年的田地里,一年又一年长出新的谷子;完全可以相信“从读过的旧书里”人们也一定能学到新的知识。                                                ......
  • 尊嘟假嘟?2023年人工智能行业新诞生10家独角兽,AIGC竟占近一半
    今年的AIGC持续热了一年,从王慧文等大佬的入局,到百度发布「文心一言」,各大巨头纷纷发布大模型产品,切实地给中国人工智能赛道的融资添了一把浓烈的火。回顾这即将过去的一整年,虽然2023年投融资整体行业遇冷,各种坏消息不断,但总体而言,AI行业融资的形势相对仍处于比较热门的状态。2......
  • 热烈祝贺2023才聚PMP发展论坛成功举行!
    12月10日,2023才聚PMP发展论坛在深圳成功举行!此次论坛由才聚主办,聚焦PMP发展前沿动态以及项目经理职业发展,吸引了近千名项目管理大咖齐聚一堂,共同展望PMP美好发展未来。大会现场座无虚席1大会团队精心筹备打造完美参会体验才聚对本次论坛高度重视,在筹备之初,就明确了要将论坛打造为项......
  • 2023十大优质国产原厂品牌网络评选活动!
    助力国产替代,振兴中国芯片!“道合顺2023十大优质国产原厂品牌网络评选”正式开启~投票有机会抽中国黄金金条、华为Mate60手机,小米扫地机器人等壕礼~!戳>https://www.icdhs.com/activity/brandvote2023/?source=51......
  • F. 纪念品 - 2023HBUCM程序设计竞赛/CSP-J2019
    题面小伟突然获得一种超能力,他知道未来\(T\)天\(N\)种纪念品每天的价格。某个纪念品的价格是指购买一个该纪念品所需的金币数量,以及卖出一个该纪念品换回的金币数量。每天,小伟可以进行以下两种交易无限次:任选一个纪念品,若手上有足够金币,以当日价格购买该纪念品;卖出持有的......
  • 20231213matlab问题资料汇总
    https://bbs.csdn.net/topics/390064770https://www.ilovematlab.cn/forum.php?mod=viewthread&tid=455375&_dsign=7812fb23https://blog.csdn.net/fmber/article/details/85858771https://www.mathworks.com/help/dotnetbuilder/MWArrayAPI/html/T_MathWorks_MATL......