[ACM]【prefix】AtCoder162 RGB Triplets

Triplets

题意:给一串RGB组成的字串,计算满足两个条件的子序列数目:(1)子序列由三个互不相同的字母组成(2)任意两个字母之间的距离不能相等(一和二的距离不能等于二和三的距离)
在这里插入图片描述

思路:

本菜鸡因为缺乏经验所以一开始反应了一会儿…但感觉这种序列问题一般都是用区间(前缀和)来做。不过我一开始以为是要按照RGB这个顺序,就莫名磨了很久2333,加上很少写前缀和(菜)debug了很久(((躺尸
最外层六次循环,因为有六种排序。里面并列两个循环,第一个循环记录第三个字母从后往前的数目,同时记录第二个字母的位置;第二个循环从前往后扫描序列第一个字母,计算ans。
这样的作法时间复杂度在O(n)-O(n^2) 之间,我也不知道怎么算…只知道比常规方法的O(n^2)要快很多。跑AC用了22ms,常规作法用了63ms.
常规作法就是两层循环,分别扫描第一个字母和第二个字母。
其实本质差不多,不过记录第二个字母位置要快很多罢了。

代码:

#include<bits/stdc++.h>
using namespace std;
char s[4003];
int back[4003];
int tmp=0,last=0;
int pos[4003];
char zimu[]={'a','R','R','G','G','B','B'},zimu2[]={'a','G','B','R','B','R','G'},zimu3[]={'a','B','G','B','R','G','R'};
int main(){
	int n;
	scanf("%d",&n);
	scanf("%s",s+1);
	int cnt;
	long long ans=0;
	for(int k=1;k<=6;k++){
		cnt=tmp=last=0;
		memset(back,0,sizeof(back));
		memset(pos,0,sizeof(pos));
		for(int i=n;i>=1;i--){
			if(s[i]==zimu3[k]){
				tmp++;
			}
			if(s[i]==zimu2[k]){
				pos[++cnt]=i;
				back[i]=back[last]+tmp;
				tmp=0;
				last=i;
			}
		}
		for(int i=1;i<=n;i++){
			if(s[i]==zimu[k]){
				for(int j=1;j<=cnt;j++){
					if(pos[j]>i){
						ans+=back[pos[j]];
						if(pos[j]+(pos[j]-i)<=n&&s[pos[j]+(pos[j]-i)]==zimu3[k])ans--;
					}
				}
			}
		}
	}
 
	printf("%lld\n",ans);
}

常规作法:

#include<bits/stdc++.h>
using namespace std;
const int maxn=4005;
int nr[maxn],ng[maxn],nb[maxn];
char s[maxn];
int main(){
	int n;
	scanf("%d",&n);
	scanf("%s",s+1);
	for(int i=n;i>=1;i--){
		nr[i]+=nr[i+1];
		nb[i]+=nb[i+1];
		ng[i]+=ng[i+1];
		if(s[i]=='R')nr[i]++;
		if(s[i]=='G')ng[i]++;
		if(s[i]=='B')nb[i]++;
	}
	long long ans=0;
	for(int i=1;i<=n-2;i++){
		for(int j=i+1;j<=n-1;j++){
			if(s[i]=='R'){
				if(s[j]=='G')ans+=nb[j];
				if(s[j]=='B')ans+=ng[j];
				if(j-i+j<=n&&s[j-i+j]!=s[j]&&s[j]!=s[i]&&s[j-i+j]!=s[i])ans--;
			}
			if(s[i]=='G'){
				if(s[j]=='R')ans+=nb[j];
				if(s[j]=='B')ans+=nr[j];
				if(s[j]!=s[i]&&j-i+j<=n&&s[j-i+j]!=s[j]&&s[j-i+j]!=s[i])ans--;
			}
			if(s[i]=='B'){
				if(s[j]=='G')ans+=nr[j];
				if(s[j]=='R')ans+=ng[j];
				if(s[j]!=s[i]&&j-i+j<=n&&s[j-i+j]!=s[j]&&s[j-i+j]!=s[i])ans--;
			}
		}
	}
	printf("%lld\n",ans);
} 
发布了9 篇原创文章 · 获赞 0 · 访问量 99

猜你喜欢

转载自blog.csdn.net/weixin_45497996/article/details/105528336
RGB