长乐爆零之旅 第一天 叉叉

版权声明:八月炊火的博客如需转载请注明出处 https://blog.csdn.net/qq_34990731/article/details/82924957

本应是开心的国庆结果开心地爆零。
先上题目:
叉叉(cross,1s,128MB)
【题目描述】
现在有一个字符串,每个字母出现的次数均为偶数。接下来我们把第一次出现的字母a和第二次出现的a连一条线,第三次出现的和四次出现的字母a连一条线,第五次出现的和六次出现的字母a连一条线…对其他25个字母也做同样的操作。
现在我们想知道有多少对连线交叉。交叉的定义为一个连线的端点在另外一个连线的内部,另外一个端点在外部。
下图是一个例子,共有三对连线交叉(我们连线的时候,只能从字符串上方经过)。
在这里插入图片描述
【输入格式】
一行一个字符串。保证字符串均由小写字母组成,且每个字母出现次数为偶数次。
【输出格式】
一个整数,表示答案。
【样例输入】
abaazooabz
【样例输出】
3
【数据规模与约定】
对于30%的数据,字符串长度不超过50。
对于100%的数据,字符串长度不超过100,000。

题解:这一题是我在考场上唯一AC的题目,这一题根据计算暴力完全可以过的,所以直接暴力了,我们先在读入的时候处理一下,我们标记每一对字母,标记方法很简单,我们按照每一对出现的顺序给它们标一下序号,并且计入一下每一组字母的两个字母的位置。然后我们再去暴力枚举每一组字母,计算一下它们区间里面有多少个不是一对的字母(说人活就是有多少个数字(因为我们后面用数子代替字母,确保了唯一性),不是成对出现的),然后后面统计的总和除以2(因为如果有一个交点我们会计算两次),就ojbk了。
上代码:

#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
using namespace std;
int num[30],in[100100],out[100100],tot=0,s[30],much=0,fy[100100],vist[100100];
int main()
{
	int n,ans=0;
	string c;
//	freopen("cross.in","r",stdin);
//	freopen("cross.out","w",stdout);
	getline(cin,c);//读入一行 
	n=c.length();
	for(int i=0;i<n;i++)//第一遍处理 
	{
		if(num[c[i]-'a'+1]==0)//有一个字母出现第一次,为什么?因为我们用0表示没出现过,1表示出现过了 
		{
			tot++;//给字母打标记 
			in[tot]=i;//计录一下从几号开始 
			num[c[i]-'a'+1]=1;
			s[c[i]-'a'+1]=tot;
			fy[i]=tot;//我们用fy数组存我们处理后的对应字母的数组 
		}
		else 
		{
			num[c[i]-'a'+1]=0;
			out[s[c[i]-'a'+1]]=i;//几号结束 
			fy[i]=s[c[i]-'a'+1];
		}
	}
	for(int i=1;i<=tot;i++)
	{
		memset(vist,0,sizeof(vist));
		much=0;
		for(int j=in[i]+1;j<out[i];j++)
		{
			if(vist[fy[j]]==0)//如果这个数字还没出现过 
			{
				vist[fy[j]]=1;
				much++;
			}
			else //出现过一次了 
			{
				vist[fy[j]]=0;
				much--;
			}
		}
		ans+=much;
	}
	ans=ans/2;//因为我们对于每一个答案会算两次,所以要除以2 
	cout <<ans;
	return 0;
} 

明天又要爆零了,哎。

猜你喜欢

转载自blog.csdn.net/qq_34990731/article/details/82924957