首页 > 其他分享 >「模拟赛」暑期集训CSP提高模拟15(8.7)

「模拟赛」暑期集训CSP提高模拟15(8.7)

时间:2024-08-08 15:17:29浏览次数:9  
标签:子串 15 8.7 int manacher mid tail 模拟 回文

赛时记录:

开场看 T1,一眼 \(manacher\) 求子串回文串,听课是听了,但是不会啊。跳了。

看 T2,发现结论题,推了会结论打上走了。

打完 T2 想了会 T3、T4,无思路,回来打了 T1 暴力和特殊性质,\(30pts\),又去想 T3,还是不会,这时还剩一个小时。不行,现在才 \(130pts\),包打祭的啊,能不能翻盘看我 T1 了,决定 20min 推 T1 的 \(manacher\),拼一把,根据学长讲的点点记忆,10 min 还真推出来了,直接打,大概还剩半个小时时间的时候打完了 T1,过了所有样例,以为成功了。

之后去打了 T3 暴力,以及 T4 暴力(但 T4 打一半就结束了)。

总分 \(38+82+20+0=140pts\)

T1 我的所谓正解只拿了 \(38pts\),输出答案部分有个细节写错了;

T2 也是细节写错了。

A.串串 38pts

原题:THUPC2018 绿绿和串串

自己赛时手推的 \(manacher\) 以及手打的板子,赛后检验没问题,没 A 是因为输出答案部分没有特判这个回文串既不接头也不接尾的情况。

不是,怎么我自己打的 \(manacher\) 的代码那么长呢?

这是赛时自己打的 manacher
void manacher(){
	int tail = 0, whi = 0;
	for(int mid=2; mid<=n-1; mid++){
		if(tail > mid){
			int con = whi - (mid - whi);
			if(f[con] + mid < tail) f[mid] = f[con];
			else{
				f[mid] = tail - mid;
				for(int len=1; len<=min(n-tail, mid-f[mid]-1); len++){
					if(s[tail+len] != s[mid-(tail-mid)-len]) {f[mid] += len - 1;break;}
					if(len == min(n-tail, mid-f[mid]-1)) f[mid] += len;
				}
			}
		}
		else{
			for(int len=1; len<=min(n-mid, mid-1); len++){
				if(s[len+mid] != s[mid-len]) {f[mid] = len - 1; break;}
				if(len == min(n-mid, mid-1)) f[mid] = len;
			}
		}
		if(f[mid] and tail < mid+f[mid])
			tail = mid + f[mid], whi = mid;
		// cout<<mid<<": "<<f[mid]<<"\n";
	}
}
这是博客园粘的板子
int manacher()
{
      int len=init();
      int ans=-N,id,mx=0;
      for(int i=1;i<len;i++)
      {
          if(i<mx)p[i]=min(p[id*2-i],mx-i);
          else p[i]=1;
          while(news[i-p[i]]==news[i+p[i]])p[i]++;
          if(mx<i+p[i])id=i,mx=i+p[i];
          ans=max(ans,p[i]-1);
      }
      return ans;
}

正解:

  1. manacher 求每一个位置为回文中心的最长回文子串;

  2. 哈希 求每一个回文串的长度。

两个方法都是为了求出所有回文子串。

然后枚举每个回文子串,

  • 如果这个子串末尾是整个串的最末位,那么这个串是合法的(直接以末位翻转可以形成原串);
  • 如果这个子串是从整个串最首位开始的,且它也可作为另一个合法发回文子串的前半段,那么这个子串也合法。(翻转之后形成的串还可以再翻转直到形成原串)

code:

#include<bits/stdc++.h>
#define ll long long
#define mp make_pair
#define love cout<<"---------\n";
using namespace std;

const int N = 1e6 + 10;

int T, n, f[N], can[N];
char s[N];

void manacher(){
	int tail = 0, whi = 0;
	for(int mid=2; mid<=n-1; mid++){
		if(tail > mid){
			int con = whi - (mid - whi);
			if(f[con] + mid < tail) f[mid] = f[con];
			else{
				f[mid] = tail - mid;
				for(int len=1; len<=min(n-tail, mid-f[mid]-1); len++){
					if(s[tail+len] != s[mid-(tail-mid)-len]) {f[mid] += len - 1;break;}
					if(len == min(n-tail, mid-f[mid]-1)) f[mid] += len;
				}
			}
		}
		else{
			// cout<<s[1+mid]<<" "<<s[mid-1]<<" ";
			for(int len=1; len<=min(n-mid, mid-1); len++){
				if(s[len+mid] != s[mid-len]) {f[mid] = len - 1; break;}
				if(len == min(n-mid, mid-1)) f[mid] = len;
			}
		}
		if(f[mid] and tail < mid+f[mid])
			tail = mid + f[mid], whi = mid;
		// cout<<mid<<": "<<f[mid]<<"\n";
	}

	can[n] = true;
	for(int i=n-1; i>=2; i--){
		if(f[i]+i == n) can[i] = true;
		else if(can[f[i]+i] and i-f[i]==1) can[i] = true;
	}
	for(int i=2; i<=n; i++){
		if(can[i]) cout<<i<<" ";
	}cout<<"\n";
}

int main(){
	// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

	cin>>T;
	while(T--)
	{
		cin>>(s+1); n = strlen(s+1);
		if(n == 1){cout<<1<<"\n";continue;}
		manacher();
		for(int i=1; i<=n; i++) f[i] = can[i] = 0;
	}


	return 0;
}

B.排排

结论推的没问题,但是判一个位置 \(x\) 之后 \(x+1\) ~ \(n\) 全都出现过判错了。

题面:

image

正解:

只有 0 ~ 3 四个答案:

  • 序列本来就是有序的,答案为 0;

  • 存在一个位置 \(i\) 保证 \(a_i=i\) 并且 \(i\) 之前出现了 \([1, i-1]\) 区间内的所有数时,答案为 1;(只在 \(i\) 位操作一次即可)

  • 1 在 \(n\) 位上,\(n\) 在 1 位上时,答案为3;(先看答案为 2 的情况。此时的情况我们可以随便在不是 1 和 \(n\) 的位置操作一次使得出现答案为 2 的情况再按答案为 2 的情况操作两次)

  • 其余答案为2;(\(n\) 不在第 1 位上时,我们在第 1 位操作一次,使得 \(n\) 可以到第 \(n\) 位;再在 \(n\) 上操作一次即可。若 1 不在 \(n\) 位上,一样)

code :

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

const int N = 2e5 + 10;

int T, n, a[N];
int head[N], tail[N];

int main(){
	// freopen("in.in", "r", stdin); freopen("out.out", "w", stdout);
	ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

	cin>>T;
	while(T--)
	{
		cin>>n;
		bool f0 = true;
		for(int i=1; i<=n; i++){
			cin>>a[i];
			if(a[i] != i) f0 = false;
			head[i] = false;
		}
		if(f0){cout<<"0\n";continue;}

		if(a[1] == n and a[n] == 1){cout<<"3\n"; continue;}

		int h = a[1], t = a[1] - 1;
		for(int i=2; i<=n; i++){
			if(a[i] < h) t--;
			else if(a[i] > h + 1) t += a[i] - h - 1;
			h = max(a[i], h);
			if(!t) head[i] = true;
		}

		int w = a[n]; t = n - a[n];
		for(int i=n-1; i>=1; i--){
			if(a[i] > w) t--;
			else if(a[i] < w - 1) t += w - 1 - a[i];
			w = min(w, a[i]);
			if(!t and head[i]){
				t = -180; break;
			}
		}
		if(t == -180){cout<<"1\n"; continue;}
		if(a[1] == 1 or a[n] == n){cout<<"1\n"; continue;}

		cout<<"2\n";
	}

	return 0;
}

标签:子串,15,8.7,int,manacher,mid,tail,模拟,回文
From: https://www.cnblogs.com/YuenYouth/p/18348978

相关文章

  • 暑假集训CSP提高模拟16
    暑假集训CSP提高模拟16组题人:@Muel_imj\(T1\)P216.九次九日九重色\(100pts\)部分分\(30pts\):设\(f_{i,j}\)表示当前处理到\(P\)的第\(i\)位,\(Q\)的第\(j\)位时最大的\(k\),状态转移方程为\(f_{i,j}=\begin{cases}\max(f_{i,j-1},f_{i-1,j})&p_{i}\nmid......
  • ignite系列之15--使用ignite构建服务端application配置项
    #false为服务端模式,true为客户端模式,此处配置falseignite.clientMode=false#类对等开关,默认开启,此处需要开启ignite.peerClassLoadingEnabled=true#集群发现端口,多个节点部署时端口是一个,localPortRange=1,addresses配置成ip1:port,ip2:portignite.discoverySpi.localPort=47500ig......
  • C++竞赛初阶L1-10-第四单元-if练习(第24课)100015: 判断能否被 3,5,7 整除
    题目内容给定一个整数 x,判断它能否被 3,5,7 整除,并输出以下信息:1、能同时被 3,5,7 整除(直接输出 357,每个数中间一个空格);2、只能被其中两个数整除(按从小到大的顺序输出两个数,例如:35 或者 37 或者 57,中间用空格分隔);3、只能被其中一个数整除(输出这个除数);4、不能......
  • P1522 [USACO2.4] 牛的旅行 Cow Tours
    思路对于每个连通块求出任意两点距离的最大值\(max[u]\),然后再\(O(n^2)\)枚举任意两个连通块连接起来,答案就是两个连通块的最大值\(max\)加上中间连接的边的长度。代码#include<bits/stdc++.h>usingnamespacestd;usingPDD=pair<double,double>;constintN=......
  • 【15.PIE-Engine案例——加载Landsat 8 SR数据集】
    加载Landsat8SR数据集原始路径欢迎大家登录航天宏图官网查看本案例原始来源最终结果具体代码/***@File:Landsat8SRImages*@Time:2020/7/21*@Author:piesat*@Version:1.0*@Contact:400-890-0662*@License:(C)Copyr......
  • 【北京迅为】《stm32mp157开发板嵌入式linux开发指南》第四章 Ubuntu 启用 root 用户
         iTOP-STM32MP157开发板是基于意法半导体STARM双Cortex-A7核加单Cortex-M4核的一款多核异构处理器。Cortex-A7内核提供对开源操作系统Linux的支持,借助Linux系统庞大而丰富的软件组件处理复杂应用。M4内核上运行对于实时性要求严格的应用。        开发板既有......
  • 8.7今日学结构体
    1.结构体数组存储学生信息(姓名,年龄,分数),完成输入学生信息,输出学生信息,求学生成绩之和,求最低学生成绩。#include<myhead.h>typedefstruct{ charname[20]; intage; intscore;}stu;intmain(intargc,constchar*argv[]){ /*结构体数组存储学生信息(姓名,年龄,分......
  • 8.7 模拟赛
    \(x+y+z\)表示赛时预计\(x\)分,实际\(y\)分,赛后补了\(z\)分。4.5小时5道题。有一道炼石的题,那场我们打过,当时那题场切了。但是现在不会做了【】有一道CF某div.2F的弱化。没做出来【】T1.降温赛时想出了做法,拍了一点小数据。但是最后被浮点数的精度和__int128......
  • 2024.8.7鲜花
    夏日重现,补完力!前年追到了18集,后因该死的集训被迫中断,但还是偶尔在机房与Ryder共赏,剧透了潮复活的情节,今夕是何年。可惜曲终人散,各奔东西,转眼间已分别半年,再过三个月我也将与机房断开联系,回归或许枯燥的文化课。牢波,想你了!刚开始接触这部番,是因为我和我姐前年暑假去表哥家玩,我......
  • CSP15
    T1唐了点击查看代码#include<bits/stdc++.h>#defineullunsignedlonglongusingnamespacestd;constintN=1E6+6;constullB=233;intlen;ullh[N],fh[N],p[N];ullget(intl,intr){ returnh[r]-h[l-1]*p[r-l+1];}ullfget(intl,intr){ inttl=len-......