超级码力在线编程大赛初赛 第2场 【题解】

三角魔法
思路

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;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

星空皓月

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

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

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

打赏作者

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

抵扣说明:

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

余额充值