三角魔法
思路
1.利用叉乘判断点是否在直线的逆时针方向
2.如果点是在三条边的逆时针方向,则点在三角形内。
3.坑点
:判断三点是否形成三角形,也是利用叉乘判断。
AC代码
class Solution {
public:
string castMagic(vector<vector<int>> &triangle, vector<int> &point) {
bool flag = isInside((double)point[0], (double)point[1], (double)triangle[0][0], (double)triangle[0][1], (double)triangle[1][0], (double)triangle[1][1], (double)triangle[2][0],(double)triangle[2][1]);
if (flag) {
return "Yes";
}
return "No";
}
double crossProduct(double x1, double y1, double x2, double y2) {
return x1 * y2 - x2 * y1;
}
bool isInside(double x, double y, double x1, double y1, double x2, double y2,
double x3, double y3) {
//特判是否形成三角形
if (crossProduct(x3 - x1, y3 - y1, x2 - x1, y2 - y1) == 0) {
return false;
}
//注意输入点的顺序不一定是逆时针,需要判断一下
if(crossProduct(x3 - x1, y3 - y1, x2 - x1, y2 - y1) >= 0)
{
double tmpx = x2;
double tmpy = y2;
x2 = x3;
y2 = y3;
x3 = tmpx;
y3 = tmpy;
}
if(crossProduct(x2 - x1, y2 - y1, x - x1, y - y1) < 0) return false;
if(crossProduct(x3 - x2, y3 - y2, x - x2, y - y2) < 0) return false;
if(crossProduct(x1 - x3, y1 - y3, x - x3, y - y3) < 0) return false;
return true;
}
};
区间异或
思路
线段树模板题,区间最大最小值,然后再异或于最大+最小值。
AC代码
#define ls (rt << 1)
#define rs (rt << 1 | 1)
const int MAXN = 5e4 + 5;
int arr[MAXN],mx[MAXN << 2],mi[MAXN << 2];
class Solution {
public:
void pushUp(int rt){
mx[rt] = max(mx[ls], mx[rs]);
mi[rt] = min(mi[ls], mi[rs]);
}
void build(int rt, int l, int r){
if (l == r){
mx[rt] = mi[rt] = arr[l];
return;
}
int m = (l + r) >> 1;
build(ls, l, m);
build(rs, m + 1, r);
pushUp(rt);
}
int query_mi(int rt, int l, int r, int L, int R){
if(L <= l && r <= R){
return mi[rt];
}
int m = (l + r) >> 1;
int ans = (1 << 30);
if(L <= m) ans = min(ans, query_mi(ls, l, m, L, R));
if(m < R) ans = min(ans, query_mi(rs, m + 1, r, L, R));
return ans;
}
int query_mx(int rt, int l, int r, int L, int R){
if(L <= l && r <= R){
return mx[rt];
}
int m = (l + r) >> 1;
int ans = -1;
if(L <= m) ans = max(ans, query_mx(ls, l, m, L, R));
if(m < R) ans = max(ans, query_mx(rs, m + 1, r, L, R));
return ans;
}
int Intervalxor(vector<int> &num, vector<vector<int>> &ask) {
int len = num.size();
for (int i = 0; i < len; ++i) {
arr[i + 1] = num[i];
}
build(1, 1, len);
int ans = 0;
for (int i = 0; i < ask.size(); ++i) {
int x = query_mx(1, 1, len, ask[i][0], ask[i][1]);
int y = query_mi(1, 1, len, ask[i][2], ask[i][3]);
ans ^= x + y;
}
return ans;
}
};
五字回文
思路
可以用中心扩展法则,但是由于长度很小,可以直接暴力做即可。
AC代码
class Solution {
public:
int Fivecharacterpalindrome(string &s) {
int len = s.size();
int ans = 0;
for (int i = 0; i < len; ++i) {
if (i >= 2 && i < len - 2) {
if (s[i - 1] == s[i + 1] && s[i - 2] == s[i + 2] && s[i] != s[i - 1] && s[i] != s[i - 2] && s[i - 1] != s[i - 2]) {
ans++;
}
}
}
return ans;
}
};
小栖的金字塔
施罗德数的递推式是这样的
前几项为1, 2, 6, 22, 90, 394, 1806, 8558, 41586, 206098。。。
但是要计算Fn,需要O(n²)的复杂度,所以需要用大施罗德数(超级卡特兰数)
这个数的前几项为1, 1, 3, 11, 45, 197, 903, 4279, 20793, 103049,发现除了第一项,后面所有的都是施罗德数的一半,所以利用超级卡特兰数来解决这个问题。
转化一下Fn = (6 * n - 3) * Fn - 1 - (n - 2) * Fn - 2 / (n + 1)
;
然后利用逆元(费马小定理的推导式)
由费马小定理得:
b(p-1) % p = 1 则:
b * b(p-2) % p = 1 两边同乘a/b,然后左右式交换得:
a / b = a / b * b * b(p-2) % p 化简得:
a / b=a * b(p-2) % p
AC代码
typedef long long ll;
const int maxn = 1e7 + 5;
const int mod = 1e9 + 7;
ll dp[maxn];
class Solution {
public:
ll fast_power(ll a, ll b) {
int res = 1;
while (b > 0) {
if (b & 1) {
res = res * a % mod;
}
b >>= 1;
a = a * a % mod;
}
return res % mod;
}
int pyramid(int n, vector<int> &k) {
int len = k.size();
dp[0] = dp[1] = 1;
for (int i = 2; i <= n; ++i) {
dp[i] = ((6 * i - 3) * dp[i - 1] % mod - (i - 2) * dp[i - 2] % mod + mod) % mod * fast_power(i + 1, mod - 2) % mod;
}
ll ans = 0;
for (int i = 0; i < len; ++i) {
if (n - k[i] == 0) {
ans = (ans % mod + dp[n - k[i]] % mod) % mod;
} else{
ans = (ans % mod + 2 * dp[n - k[i]] % mod) % mod;
}
}
return (int)ans;
}
};