【CCPC】2022河南省赛补题记录-BI

190 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情

解题记录

B Hash

题目大意

对于一个字符串 S=s1s2...sSS=s_1s_2...s_{|S|},定义其 Hash 函数为

f(S)=(i=1Sg(si)×31Si)mod998244353f(S)=(\sum^{|S|}_{i=1}g(s_i)\times 31^{|S|−i})\mod 998244353

环形字符串 T=t1t2...tTT=t_1t_2...t_{|T|} 仅包括 a,e,h,n 四种字母,且 g(a)=1,g(e)=2,g(h)=3,g(n)=4g(a)=1,g(e)=2,g(h)=3,g(n)=4 。且长度不超过 200000。试将其划分成若干个连续子段 S1,S2,...,SkS_1,S_2,...,S_k,最大化 f(S1)+f(S2)+...+f(Sk)f(S_1)+f(S_2)+...+f(S_k)

思路

易知一段连续子段的最大值不会超过 998244353,所以我们不会把连续子段划分的太长。

我们可以枚举第一个段的第一个元素将环展开,令 dp[i] 表示前 i 个字符能划分出的最大和,则转移方程为:

dp[i]=maxj=max(iD,0)i1{dp[j]+f(tj+1...ti)}dp[i]=\max^{i-1}_{j=\max(i-D,0)}\{dp[j]+f(t_{j+1}...t_i)\}

暴力跑出来最长子段的长度不会超过15。题解给出了证明:

image.png

image.png

image.png

代码

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;
char a[200021];
long long w[200021],dp[200021],d[21],ans;
int n;
int main()
{
    cin>>a+1;
	n=strlen(a+1);
	for (int i=1;i<=n;i++)
		if (a[i]=='a') w[i]=1;
	    else if (a[i]=='e') w[i]=2;
	    else if (a[i]=='h') w[i]=3;
	    else if (a[i]=='n') w[i]=4;
	for (int l=1,r;l<=16;++l)
	{
		r=l+n-1;
		w[r+1]=w[l];
		memset(d,0,sizeof(d));
		memset(dp,0,sizeof(dp));
        for (int i=l;i<=r;i++)
			for (int j=16;j>=1;--j)
			{
				d[j]=(d[j-1]*31+w[i])%998244353;
				if (i-j>=0) dp[i]=max(dp[i],dp[i-j]+d[j]);
			}
		ans=max(ans,dp[r]);
	}
	printf("%lld",ans);
	return 0;
}

I Oshwiciqwq 的电梯

题目大意

有一个长方体大楼,长 n 个 单位,宽 m 个单位,高 h 个单位。这个大楼里每个长宽高各为 1 个单位的空间是一个房间,可以用三维坐标 (x,y,z)(x, y, z) 来表示,其中 1xn,1ym,1zh1 ≤ x ≤ n, 1 ≤ y ≤ m, 1 ≤ z ≤ h

大楼有 k 个电梯,每个电梯是朝坐标增大的方向环线运行的,在坐标最大处可以运行一次.瞬移到坐标最小处。不同电梯的运行轨道不相交。 保证了每两个房间之间都是间接可达的。所有电梯运行一个单位的时间为 1 秒,容量为无穷大。

每个电梯初始所在位置不同,第 i 个电梯 0 秒时在坐标为 (exi,eyi,ezi)(ex_i , ey_i , ez_i) 的房间。电梯只能在整秒时刻开始移动或者结束移动,并且在电梯到达某房间后,乘客会在到达的同一时刻瞬移进出电梯门。

有 q 个乘客,第 i 个乘客在 ptipt_i 秒到达,想要从位于 (fxi,fyi,fzi)(fxi , fyi , fzi ) 的房间到达位于 (txi,tyi,tzi)(txi , tyi , tzi) 的房间。

规定乘客的路线为: (fxi,fyi,fzi)(txi,fyi,fzi)(txi,tyi,fzi)(txi,tyi,tzi)(fxi , fyi , fzi ) → (txi , fyi , fzi ) → (txi , tyi , fzi ) → (txi , tyi , tzi),即按顺序先后乘坐平行 x 轴,y 轴与 z 轴的电梯。如果某个阶段无需乘坐电梯已经到达,则直接忽略。在乘客进行某个阶段的移动时,只会搭乘对应方向的电梯。 具体运行策略如下:

  1. 电梯一开始在给定的坐标,方向为平行于对应坐标轴的正方向,一直环线运行
  2. 每到达一个房间,所有到达当前阶段目的地的乘客会按编号从小到大下电梯。然后在这个房间的乘 客会按编号从小到大上电梯。一个乘客下电梯之后,如果还没有到达最终目的地,那么会在原地等待下一个电梯,换乘至少需要一秒的时间。在出电梯的下一秒才能进入另一个电梯。
  3. 同一时刻编号小的电梯的所有进出事件发生在编号大的电梯前。

输出乘客上下电梯的信息。

思路

模拟,数据范围很小不会TLE。

我使用了结构体来简便代码的编写。

代码

#include <stdio.h>
#include <algorithm>
#include <queue>
using namespace std;
int wall[3],k,q;
struct cell{
	int x[3];
	void get()
	{
		scanf("%d%d%d",&x[0],&x[1],&x[2]);
	}
	bool operator != (const cell c) const
	{
		if (x[0]!=c.x[0]) return 1;
		if (x[1]!=c.x[1]) return 1;
		if (x[2]!=c.x[2]) return 1;
		return 0;
	} 
};
struct ele{
	cell cl;
	int type;
	void nxt()
	{
		cl.x[type]++;
		if (cl.x[type]>wall[type]) cl.x[type]=1;
	}	
}e[301];
struct people{
	cell cl,to;
	int t,flg,eleid;
	int geteltype()
	{
		if (cl.x[0]!=to.x[0]) return 0;
		if (cl.x[1]!=to.x[1]) return 1;
		if (cl.x[2]!=to.x[2]) return 2;
		return 3;
	}
}p[51];
int allpeoplearriveddestination()
{
	for (int i=1;i<=q;++i)
		if (p[i].geteltype()!=3) return 0;
	return 1;
}
//priority_queue<int> peopleid[301];
int main()
{
	scanf("%d%d%d",&wall[0],&wall[1],&wall[2]);
	int T=0;
	scanf("%d",&k);
	for (int i=1;i<=k;++i)
	{
		scanf("%d",&e[i].type);
		e[i].cl.get();
	}
	scanf("%d",&q);
	for (int i=1;i<=q;++i)
	{
		scanf("%d",&p[i].t);
		p[i].cl.get();
		p[i].to.get();
	}
	while (1)
	{
		T++;
		if (allpeoplearriveddestination()) return 0;
		for (int i=1;i<=k;++i)
		{
			e[i].nxt();
			for (int j=1;j<=q;++j)
			{
				if (p[j].eleid!=i) continue;
				p[j].cl=e[i].cl;
				if (p[j].geteltype()==e[i].type) continue;
				p[j].flg=1;
				p[j].eleid=0;
				printf("[%ds] Person %d OUT Elevator %d at (%d, %d, %d)\n",T,j,i,e[i].cl.x[0],e[i].cl.x[1],e[i].cl.x[2]);
			}
			for (int j=1;j<=q;++j)
			{
				if (p[j].flg) continue;
				if (p[j].t>T) continue;
				if (p[j].cl!=e[i].cl) continue;
				if (p[j].geteltype()!=e[i].type) continue;
				if (p[j].eleid!=0) continue;
				p[j].eleid=i;
				printf("[%ds] Person %d IN Elevator %d at (%d, %d, %d)\n",T,j,i,e[i].cl.x[0],e[i].cl.x[1],e[i].cl.x[2]);
			}
		}
		for (int j=1;j<=q;++j) p[j].flg=0;
	}
}