2023牛客暑期多校训练营8(A/H/I/J)

目录

A.Alive Fossils

 H.Insert 1, Insert 2, Insert 3, ...

I.Make It Square

J.Permutation and Primes


A.Alive Fossils

思路:一开始题意看半天没看懂,后面发现只需要输出t组输入中,都出现过的字符串即可。

代码:

void solve() {
	int t;
	cin>>t;
	for(int i=1;i<=t;i++){
		int n;
		cin>>n;
		for(int i=1;i<=n;i++){
			string s;
			cin>>s;
			mp[s]++;
		}
	}
	vectorans;
	for(auto x:mp){
		if(x.second==t){
			ans.push_back(x.first);
		}
	}
	cout<

 H.Insert 1, Insert 2, Insert 3, ...

思路:根据题意我们可以发现,因为数字是按顺序1,2,3......插,所以若一段区间[l,r]满足条件,那么[l,r'](r'<=r)也必然满足条件。我们可以从后往前遍历,也就是遍历区间[i,n](i从n遍历到1)。每次遍历到a[i]时,因为插入是顺序的,所以这个a[i],一定能和a[i]+1这个值对应,把它“抵消”掉,所以若一个区间合法,那么这个区间会被“抵消”完,第i个点的贡献为最左边的没被抵消完的端点-i。

举个例子吧,拿样例一来说,它的序列为:

1 1 2 2 3 3

从后往前遍历,遍历了i=5以及i=6,此时存入了两个3,它们都不合法:

不合法的值:3 3

不合法的下标:5 6

贡献为:最左边的没被抵消完的端点-i=5-5=0

然后遍历到i=4,此时a[i]=2,他能与一个a[i]+1抵消,也就是把3给抵消了,此时:

不合法的值:2 3

不合法的下标:4 6

贡献为:最左边的没被抵消完的端点-i=4-4=0

然后遍历到i=3,此时a[i]还是2,他还是能把3抵消,此时:

不合法的值:2 2

不合法的下标:3 4

贡献为:最左边的没被抵消完的端点-i=3-3=0

然后遍历到i=2,此时a[i]是1,他能把一个2抵消,此时:

不合法的值:2 (1不放入不合法的值中,因为单个1合法)

不合法的下标:4

贡献为:最左边的没被抵消完的端点-i=4-2=2

然后遍历到i=1,此时a[i]还是1,他能把一个2抵消,此时:

不合法的值: 无(1不放入不合法的值中,因为单个1合法)

不合法的下标:无

此时后面都合法了,贡献为i~n整个区间也就是6

总贡献为 :0+0+0+2+6=8

代码:

vectorans,pos[maxn];
//ans存最入不满足条件的点
//pos[x]存入a[i]=x的位置
int a[maxn],st[maxn];
void solve() {
	int n,res=0;
	cin>>n;
	ans.push_back(n+1);//放入初始值,使得:若点i后面没有不满足条件的点,则答案加n-i+1,也就是i~n区间的贡献。
	for(int i=1; i<=n; i++)cin>>a[i];
	for(int i=n; i>=1; i--) {
		if(pos[a[i]+1].size()) {
			st[pos[a[i]+1].back()]=true;//这个点被上一个点"抵消"了,标记这个点已经合法了
			pos[a[i]+1].pop_back();//消掉
		}
		if(a[i]>1) {
			pos[a[i]].push_back(i);//存入值对应的下标
			ans.push_back(i);//存入不合法的位置
		}
		while(st[ans.back()])ans.pop_back();//把合法的都弹出
		res+=ans.back()-i;
	}
	cout<

I.Make It Square

思路:若字符串s的长度小于t,我们将两个字符串翻转后交换,仍可以使得字符串s大于t,所以我们考虑s长度大于t的情况。

通过手玩样例我们可以发现,随着字符串p和q长度的增加,对于字符串s,分割点是固定的,分割点在后缀大小为(s.size()-t.size())/2。举个例子,比如样例三:

s=abbabbababbab,t=bab。

当p.size()=q.size()=1时:

 p+s+q+t=?abbabbababbab?bab

分割为 ?abbabbab  abbab?bab

当p.size()=q.size()=2时:

 p+s+q+t=??abbabbababbab??bab

分割为 ??abbabbab  abbab??bab

以??abbabbab  abbab??bab举例,

首先,若bab与abbabbab的后缀不重合,那么这两个部分的字符串怎么都不会相等。然后可以看出,我们可以通过字符串abbabbab作为后缀,字符串abbab作为前缀,来求出已经不固定的字符个数。

若这两个部分有重合,则判断重合部分是否一样,也就是abbabbab的重合前缀和abbab重合后缀是否一样,利用z函数判断即可,若重合部分一样则答案为1,反之答案为0。

若这两个部分没重合,则计算不固定字符的个数,答案为26的幂次。

具体实现见代码:

代码:

vector zFunction(string s) {
	int n = s.size();
	vector z(n + 1);
	z[0] = n;
	for (int i = 1, j = 1; i < n; i++) {
		z[i] = max(0ll, min(j + z[j] - i, z[i - j]));
		while (i + z[i] < n && s[z[i]] == s[i + z[i]]) {
			z[i]++;
		}
		if (i + z[i] > j + z[j]) {
			j = i;
		}
	}
	return z;
}
void solve() {
	k26[0]=1;
	for(int i=1; i>n>>s>>t;
	int lens=s.size(),lent=t.size();
	if((lens+lent)%2) {//若字符串长度之和为奇数,那么它们怎么都不能分割成两个相等字符串
		for(int i=1; i<=n; i++)cout<<0<<" ";
		return;
	}
	if(lensnow) {//若有重合部分
			if(v[p]!=p) cout<<0<<" ";//重合部分是否全部相同
			else cout<<1<<" ";//答案为加1
		} else {
			cout<

J.Permutation and Primes

思路:我们可以先构造长度为7的循环节:

i+3,i+6,i+1,i+4,i+7,i+2,i+5

那么若n%7不为0的时候怎么办呢?我们可以先把前面的长度为7循环节给赋值,然后最后7+n%7个数,我们随便找一组解满足它与循环节的末尾形成奇质数,放预处理后面即可。

代码:

int cmp[7][15] {
	{3,6,1,4,7,2,5},//长度为7的循环节
	{5,2,7,4,1,8,3,6},//最后8个数,此时n%7=1
	{9,6,3,8,5,2,7,4,1},//最后9个数,此时n%7=2
	{9,4,7,2,5,10,3,8,1,6},//最后10个数,此时n%7=3
	{11,8,5,10,7,2,9,4,1,6,3},//最后11个数,此时n%7=4
	{1,6,3,10,7,12,5,2,9,4,11,8},//最后12个数,此时n%7=5
	{1,4,9,2,7,12,5,10,3,6,13,8,11}//最后13个数,此时n%7=6
};
void solve() {
	cin>>n;
	int k=n/7;
	if(n==2) {
		cout<<"1 2"<

你可能感兴趣的:(牛牛的暑假,算法,c++,数据结构)