原题链接.
1.题意:
给个无穷大的正六边形棋盘,可以画若干条过六边形对立顶点的直线,问这些直线最多可以构成多少个三角形。
2.思路:
刚看题其实自己是挺蒙的,主要由于自己总局限于六边形之中,没有跳出来,用抽象的眼光看问题。
后来在模拟中发现3点结论
- 直线只有3种斜率
- 2条斜率不同的直线,必然存在一个六边形,使得二者的交点为六边形中心
- 只要2条直线相交,就会产生2个三角形。(当时我从简单情况入手,在研究3条斜率不同的直线产生的三角形个数。发现当三条线交于一个六边形时,三角形个数为6;交于三个六边形时,三角形个数为3*2=6,然后突然意识到此结论是有利于解题的。还是思路和感觉吧,主要靠感觉。)
由此,我将此问题抽象为求n条直线最多交点数的问题。
然后根据贪心,可知不同斜率的直线的数量之差不得大于1,否则一定可以把较多数量的直线k1,变成较少数量的直线k2,此时交点数至少增加1(画个图就一目了然)。那么我们可以轮流将三种斜率的线画进来,得到的就是最优解。
3.代码
#include <bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define mp make_pair
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
const int Mod=1e9+7,N=1e6+10;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int sol(int n){
int x = sqrt(n/6);
int a=x*4,d=n-6*x*x;
if(d==0)return 3*x;
else if(a>=d)return 3*x+1;
else if(a+a+2>=d)return 3*x+2;
else return 3*x+3;
}
int main()
{
int t;
cin>>t;
while(t--){
int n;
cin>>n;
cout<<sol(n)<<endl;
}
}
4.收获
- 此题将六边形棋盘的问题抽象为直线交点问题,无疑是一道好题
- 理解了一个简单的贪心模型,就是求m种斜率的直线交点个数的问题。