Hyperset(排序+二分)

Bees Alice and Alesya gave beekeeper Polina famous card game “Set” as a Christmas present. The deck consists of cards that vary in four features across three options for each kind of feature: number of shapes, shape, shading, and color. In this game, some combinations of three cards are said to make up a set. For every feature — color, number, shape, and shading — the three cards must display that feature as either all the same, or pairwise different. The picture below shows how sets look.
在这里插入图片描述

Polina came up with a new game called “Hyperset”. In her game, there are nn cards with kk features, each feature has three possible values: “S”, “E”, or “T”. The original “Set” game can be viewed as “Hyperset” with k=4k=4.

Similarly to the original game, three cards form a set, if all features are the same for all cards or are pairwise different. The goal of the game is to compute the number of ways to choose three cards that form a set.

Unfortunately, winter holidays have come to an end, and it’s time for Polina to go to school. Help Polina find the number of sets among the cards lying on the table.

Input
The first line of each test contains two integers nn and kk (1≤n≤15001≤n≤1500, 1≤k≤301≤k≤30) — number of cards and number of features.

Each of the following nn lines contains a card description: a string consisting of kk letters “S”, “E”, “T”. The ii-th character of this string decribes the ii-th feature of that card. All cards are distinct.

Output
Output a single integer — the number of ways to choose three cards that form a set.

Examples
Input
3 3
SET
ETS
TSE
Output
1
Input
3 4
SETE
ETSE
TSES
Output
0
Input
5 4
SETT
TEST
EEET
ESTE
STES
Output
2
Note
In the third example test, these two triples of cards are sets:

“SETT”, “TEST”, “EEET”
“TEST”, “ESTE”, “STES”

很久没有做算法题了,这个题不算难,但是还是手生。
首先容易想到的是O(n^3)的算法,但是一定会超时。因此我们可以固定两个,根据两个字符串找出另一个字符串,然后判断另外一个字符串有没有出现。这样时间复杂度就降到了O(n ^ 2),但是一开始用的map超时了,stl毕竟耗时大。我们可以事先对字符串排个序,这样就可以二分来找那个字符串。但是不能用SET了,要转化成对应的1,2,3。这样异或起来,如果是0的话,就是原来的数字,如果不是0的话,这样就是异或之后的那个数字。排序之后二分,就可以判断那个数字有没有存在了。除此之外,最后的结果要除以三才是最终的答案,因为一样的式子,我们找了三遍。
代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;

const int maxx=1e4+100;
string s[maxx];
int n,m;

inline string fcs(string a,string b)
{
	string c="";
	int x,y;
	for(int i=0;i<m;i++)
	{
		x=a[i]-'0';
		y=b[i]-'0';
		if((x^y)==0) c+=(x+'0');
		else c+=((x^y)+'0');
	}
	return c;
}
int main()
{
	scanf("%d%d",&n,&m);
	int cnt=0;
	for(int i=0;i<n;i++)
	{
		cin>>s[i];
		string a="";
		for(int j=0;j<m;j++)
		{
			if(s[i][j]=='S') a+='1';
			else if(s[i][j]=='E') a+='2';
			else a+='3';	
		}
		s[i]=a;
	}
	int ans=0;
	sort(s,s+n);
	//for(int i=0;i<n;i++) cout<<s[i]<<endl;
	for(int i=0;i<n;i++)
	{
		for(int j=i+1;j<n;j++)
		{
			string t=fcs(s[i],s[j]);
			int l=0,r=n-1;
			while(l<=r)
			{
				int mid=l+r>>1;
				if(s[mid]==t) 
				{
					ans++;
					break;
				}
				else if(s[mid]>t) r=mid-1;
				else l=mid+1;
			}
		}
	}
	printf("%d\n",ans/3);
	return 0;
}

努力加油a啊,(o)/~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

starlet_kiss

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值