此题你从特殊情况开始考虑就3中 点是直线 点形成凸包 点形成凸包且凸包内有一些点然后
主要就是注意某些点他如果和其他点在同一个集合中时,那么这个集合一定不只是有这两个点,所以我们让这类点颜色相同就好了
no的情况只有n=1 2 3的时候才是可能的
1.直线的话就是除开两端的点外随便让一个点是‘A'其他是'B’就好了
2.凸包的话隔一个点是'A'其他是'B'
3.凸包里有个点的话,凸包内的那个点是‘B'其余是'A'当然颜色你随便弄只要不相同就好
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
int map[1050][1050];
int color[1050];
int tot,top;
int n;
struct pointt
{
int x, y;
pointt()
{}
};
pointt point[6000], tubao[6000];
pointt gett[1020];
pointt operator-(pointt a, pointt b)
{
pointt c;
c.x = a.x - b.x; c.y = a.y - b.y;
return c;
}
double dot(pointt a, pointt b)
{
return a.x*b.y - a.y*b.x;
}
double dist(pointt a, pointt b)
{
double kk = (double)((a.x - b.x)*(a.x - b.x) + (a.y - b.y)*(a.y - b.y));
return sqrt(kk);
}
struct linee
{
pointt p1, vec;
linee(pointt a, pointt b) :p1(a), vec(b - a)
{}
linee()
{}
};
linee shape[6000];
bool com(pointt a, pointt b)
{
double t = dot(a - point[0], b - point[0]);
if (t == 0)
return dist(a, point[0]) < dist(b, point[0]);
return t > 0;
return false;
}
int isonleft(pointt test, linee std)
{
pointt c = test - std.p1;
if (dot(c, std.vec) == 0)//这种情况只要有三点共线马上出去。
{
for (int i = 0; i < n; i++)color[i] = 'B';
color[map[test.x][test.y]] = 'A';//这我们吧中间那个点涂上‘A';
return 2;
}
return dot(c, std.vec) <=0;
}
bool check()//检查是否所有点都在一条直线上
{
for (int i = 2; i <n; i++)
{
pointt a, b;
a = point[i] - point[1];
b = point[i + 1] - point[1];
if (dot(a, b) != 0)return false;
}
return true;
}
bool judge = 1;
void graham()
{
//for (int i = 1; i <= n; i++)
//{
// cout << "x:" << point[i].x << " " << "y:" << point[i].y << endl;
//}
tubao[0] = point[1]; tubao[1] = point[2]; //shape[0] = linee(tubao[0], tubao[1]);
int last = 1; int tempjudge = -1;
for (int i = 3; i <= n; i++)
{
while (last >= 1 && (tempjudge = isonleft(tubao[last], linee(tubao[last - 1], point[i]))) && (tempjudge != 2))
{
gett[top++] = tubao[last];
last--;
}
if (tempjudge == 2)
{
return;
}
tubao[++last] = point[i];
}
if (last == n - 1)//全在凸包上
{
for (int i = 0; i < n; i++)
color[map[tubao[i].x][tubao[i].y]] = 'B';
color[map[tubao[0].x][tubao[0].y]] = 'A';
color[map[tubao[2].x][tubao[2].y]] = 'A';
return;
}
else//有凸包但里面有个点
{
for (int i = 0; i < n; i++)
color[i] = 'B';
color[map[gett[top - 1].x][gett[top - 1].y]] = 'A';
}
}
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
scanf("%d", &n);
judge = 1;
if (n <=2)
{
for (int i = 0; i < n; i++){
int a, b;
scanf("%d%d", &a, &b);
}
printf("NO\n"); continue;
}
pointt min;
min.x = 1000000000; min.y = 1000000000;
tot = 0, top = 0;
for (int i = 1; i <= n; i++)
{
int a, b;
scanf("%d%d", &a, &b);
map[a][b] = tot++;
point[i].x = a; point[i].y = b;
if (b < min.y || (b == min.y&&a < min.x))
min = point[i];
}
point[0] = min;
sort(point + 1, point + n + 1, com);
if (n == 3)
{
if (check())//检查是否共线
{
for (int i = 0; i <n; i++)color[i] = 'B';
color[map[point[2].x][point[2].y]] = 'A';
printf("YES\n");
for (int i = 0; i < n; i++)
printf("%c", color[i]);
printf("\n");
continue;
}
else
{
judge = 0;
printf("NO\n");
}
continue;
}
else
graham();
printf("YES\n");
if (judge)
for (int i = 0; i < n; i++)
printf("%c", color[i]);
printf("\n");
}
return 0;
}
b题:
此题我还不太会高精所以木有写,说一下思路吧,想开始想的是动态规划,后来在大神的指引下朝着组合数学的方向思考了。。
其实我们就是要确定字符串每个字符的等级就好了。试想,如果给你后缀数组,然后再给出每个字母多少个,那么组合就唯一确定了。所以此题就是要根据后缀数组确定各个字符的等级然后再用插板法进行计数。
用插板法的时候对于样例我算的是C(30)(7)我是将7=5+2即是将5个字母和两个板捆绑在一起算的,但是你是不能这样算的为什么呢?因为当你放好了这7个物体后你再插板,由于板都是一样的所以你中间插得两个版将会和其他版混淆,导致重复计数,正确的做法是c(28)(5)的为什么是28 因为28=23+5 23=26-3 减去的3是中间放的两个版和最后一个一定固定有一个版 这样的思路就是 先拿出三个版 然后现在还剩28个位置 将5个字符先放好,然后三个版都是有固定位置的放就好了