老曹的忧郁(数学)

老曹的忧郁

题目大意

给你一个 n 行的图,第 i 行有 n 个数,所有数放在一起形成了一个等边三角形。
然后问你有多少个数,满足它出现的位置中可以选出三个,它们为顶点形成的三角形是等边三角形。

思路

我们考虑枚举每个等边三角形,然后判断顶点颜色。

然后我们考虑如何统计到所有的等边三角形。
在这里插入图片描述
你会发现,这样同一个颜色的组成的三角形都是等边三角形。

这有什么特点呢?
一开始三个粉色的很好确定,那剩下的呢?
红色的可以由粉色顺时针移动一下得到,再移动一些就是橙色,然后是黄色。。。

考虑用这个方法来统计,那首先要枚举这个三角形的位置(我这里枚举的是上面粉色的位置),接着就是枚举这个三角形的大小,然后再一位一位移。

那怎么确定三个的位置呢?
我们考虑让 ( i , j ) (i,j) (i,j) 为第 i i i 行第 j j j 个。
然后我们想一想,我们假设上面的粉色是 ( x , y ) (x,y) (x,y),三角形大小是 l l l,那左边右边的粉色就分别是: ( x + l − 1 , y ) , ( x + l − 1 , y + l − 1 ) (x+l-1,y),(x+l-1,y+l-1) (x+l1,y),(x+l1,y+l1)
然后假设顺时针动了 p p p 次,三个的位置就变成了 ( x + p − 1 , y ) , ( x + l − 1 , y + p − 1 ) , ( x + l − 1 − p + 1 , y + l − 1 − p + 1 ) (x+p-1,y),(x+l-1,y+p-1),(x+l-1-p+1,y+l-1-p+1) (x+p1,y),(x+l1,y+p1),(x+l1p+1,y+l1p+1)

然后就可以啦。

代码

#include<cstdio>

using namespace std;

int n, m, pp[101][101];
char c[101];
bool yes[31], no;

struct pl {
	int x, y;
}a[101], ii, jj, kk;

pl get_pl(int now) {
	pl re;
	re.x = 1; re.y = 0;
	while (now > re.x) {
		now -= re.x;
		re.x++;
	}
	re.y = now;
	return re;
}

int main() {
	scanf("%d", &n);
	m = n * (n + 1) / 2;
	scanf("%s", c + 1);
	
	for (int i = 1; i <= m; i++) a[i] = get_pl(i), pp[a[i].x][a[i].y] = i;
	
	no = 1;
	for (int i = 1; i <= m; i++) {//枚举大三角上面的顶点
		for (int l = 2; a[i].x + l - 1 <= n; l++) {//枚举大三角的大小
			for (int p = 1; p < l; p++) {//枚举转的大小
				int x = pp[a[i].x + p - 1][a[i].y];//得到三个点
				int y = pp[a[i].x + l - 1][a[i].y + p - 1];
				int z = pp[a[i].x + l - 1 - p + 1][a[i].y + l - 1 - p + 1];
				if (c[x] == c[y] && c[y] == c[z]) {//判断是否颜色相同
					no = 0;
					yes[c[x] - 'a'] = 1;
				}
			}
		}
	}
	
	if (no) printf("Harmonious");
		else {
			for (int i = 0; i < 26; i++)
				if (yes[i]) putchar(i + 'a');
		}
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值