GithubHelp home page GithubHelp logo

contests's People

Contributors

maninbule avatar

Watchers

 avatar  avatar

contests's Issues

leetcode 周赛155

1200. 最小绝对差 【简单思维】

先对数组进行从小到大排序,两个元素的最小差就一定是排序后的某两个相邻两个元素的差。
所以,先遍历排序后的数组找到最小差,然后再遍历一遍数组,将差值为最小差的元素对放入vector里面就好,并且已经是排好序的

class Solution {
public:
    vector<vector<int>> minimumAbsDifference(vector<int>& arr) {
        vector<vector<int>> res;
        sort(arr.begin(),arr.end());
        int dif = (int)1e9+7;
        for(int i = 1;i<arr.size();i++){
            dif = min(dif,arr[i]-arr[i-1]);
        }
        for(int i = 1;i<arr.size();i++){
            if(arr[i]-arr[i-1] == dif){
                vector<int> ve = {arr[i-1],arr[i]};
                res.push_back(ve);
            }
        }
        return res;
    }
};

1201. 丑数 III 【容斥原理+二分】

对于一个x,可以通过容斥原理来判断他以及之前有多少个丑数
之前丑数的个数 = int cnt = x/a+x/b+x/c-x/ab-x/ac-x/bc+x/abc;
ab为a、b的最小公倍数
这样就可以通过二分来算出第n各丑数

typedef long long ll;
class Solution {
public:
    ll a,b,c,ab,ac,bc,abc,n;
    bool judge(int x){
        int cnt = x/a+x/b+x/c-x/ab-x/ac-x/bc+x/abc;
        if(cnt<n) return false;
        return true;
    }
    ll lcm(ll a,ll b){
        return a*b/__gcd(a,b);
    }
    int nthUglyNumber(int n1, int a1, int b1, int c1) {
        n = n1,a = a1,b = b1,c = c1;
        ab = lcm(a,b),ac = lcm(a,c),bc = lcm(b,c),abc = lcm(c,ab);
        ll l = 1,r = 2e9+10,mid;
        while(l<r){
            mid = (l+r)/2;
            if(judge(mid)){
                r = mid;
            }else{
                l = mid+1;
            }
        }
        return l;
    }
};

1202. 交换字符串中的元素 【并查集】

假如可以互换的元素对有[2,3],[3,5] 那么[2,3,5]都是可以互换的,他们同属于一个联通块
所以我们需要使用并查集找出所有的联通块,对每个联通块里对应的字母进行排序,然后把排序后的字符串拷贝回原来的位置就行了。

const int maxn = 1e6+10;
class Solution {
public:
    int fa[maxn];
    map<int,vector<int>> ve;
    string str;
    int find(int x){
        if(x != fa[x])
            fa[x] = find(fa[x]);
        return fa[x];
    }
    void join(int x,int y){
        int fx = find(x),fy = find(y);
        if(fx!=fy) fa[fx] = fy;
    }
    
    void solve(int id){
        string s = "";int idx = 0;
        for(const auto &i:ve[id]){
            s+= str[i];
        }
        sort(s.begin(),s.end());
        for(const auto &i:ve[id]){
            str[i] = s[idx++];
        }
    }
    string smallestStringWithSwaps(string s, vector<vector<int>>& pairs) {
        str = s;
        
        for(int i = 0;i<s.size();i++) fa[i] = i;
        for(const auto &v:pairs){
            join(v[0],v[1]);
        }
        for(int i = 0;i<s.size();i++) find(i);
        for(int i = 0;i<s.size();i++){
            if(ve.count(fa[i]) == 0) ve[fa[i]] = vector<int>();
            ve[fa[i]].push_back(i);
        }
        for(int i = 0;i<s.size();i++){
            if(ve[i].size() == 0) continue;
            solve(i);
        }
        
        return str;
    }
};

1203. 项目管理 【拓扑排序】

这题需要多次拓扑排序,而我只会一次。实在不会写,之后变强了再补

ICPC2018 焦作站E题

E. Resistors in Parallel 【数论+大数】

image
对于R这个式子,要R最小,那么分母就应该最大,让分母最大,那么让1/Ri的分母尽可能的小,数量尽可能多。本题的主要任务就是去找一个连续素数的乘积最大但小于等于n,证明如下图片
2019-10-20 20 18 18 031
因为要让分母尽可能小,那么素数从最小的2开始,然后依次乘以下一个素数,直到乘积最大但<=n时,此时就满足了让1/Ri的分母尽可能的小,数量尽可能多。且这些质数的乘积组合都是小于等于n的因子

关于大数,使用了一个封装好的大数模板,里面有加减乘除取余,还加入了运算符重载,虽然代码量挺大,但是的确好用

#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <stdio.h>
#include <cstring>
#include <string>
# define FOR(i, a, b) for(int i = a; i <= b; i++)
# define _FOR(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
const int maxn = 1e6+10;
typedef long long ll;
struct BigInt
{
    static const int M = 1000;
    int num[M + 10], len;

    BigInt(int x) {
        clean();
        itoBig(x);
    }
    BigInt() {
        clean();
    }

    void clean(){
        memset(num, 0, sizeof(num));
        len = 1;
    }

    void read(){
        char str[M + 10];
        scanf("%s", str);
        len = strlen(str);
        FOR(i, 1, len)
            num[i] = str[len - i] - '0';
    }

    void write(){
        _FOR(i, len, 1)
            printf("%d", num[i]);
        //puts("");
    }

    void itoBig(int x){
        clean();
        while(x != 0){
            num[len++] = x % 10;
            x /= 10;
        }
        if(len != 1) len--;
    }

    bool operator < (const BigInt &cmp) const {
        if(len != cmp.len) return len < cmp.len;
        _FOR(i, len, 1)
            if(num[i] != cmp.num[i]) return num[i] < cmp.num[i];
        return false;
    }

    bool operator > (const BigInt &cmp) const { return cmp < *this; }
    bool operator <= (const BigInt &cmp) const { return !(cmp < *this); }
    bool operator != (const BigInt &cmp) const { return cmp < *this || *this < cmp; }
    bool operator == (const BigInt &cmp) const { return !(cmp < *this || *this < cmp); }

    BigInt operator + (const BigInt &A) const {
        BigInt S;
        S.len = max(len, A.len);
        FOR(i, 1, S.len){
            S.num[i] += num[i] + A.num[i];
            if(S.num[i] >= 10){
                S.num[i] -= 10;
                S.num[i + 1]++;
            }
        }
        while(S.num[S.len + 1]) S.len++;
        return S;
    }

    BigInt operator - (const BigInt &A) const {
        BigInt S;
        S.len = max(len, A.len);
        FOR(i, 1, S.len){
            S.num[i] += num[i] - A.num[i];
            if(S.num[i] < 0){
                S.num[i] += 10;
                S.num[i + 1]--;
            }
        }
        while(!S.num[S.len] && S.len > 1) S.len--;
        return S;
    }

    BigInt operator * (const BigInt &A) const {
        BigInt S;
        if((A.len == 1 && A.num[1] == 0) || (len == 1 && num[1] == 0)) return S;
        S.len = A.len + len - 1;
        FOR(i, 1, len)
            FOR(j, 1, A.len){
                S.num[i + j - 1] += num[i] * A.num[j];
                S.num[i + j] += S.num[i + j - 1] / 10;
                S.num[i + j - 1] %= 10;
            }
        while(S.num[S.len + 1]) S.len++;
        return S;
    }

    BigInt operator / (const BigInt &A) const {
        BigInt S;
        if((A.len == 1 && A.num[1] == 0) || (len == 1 && num[1] == 0)) return S;
        BigInt R, N;
        S.len = 0;
        _FOR(i, len, 1){
            N.itoBig(10);
            R = R * N;
            N.itoBig(num[i]);
            R = R + N;
            int flag = -1;
            FOR(j, 1, 10){
                N.itoBig(j);
                if(N * A > R){
                    flag = j - 1;
                    break;
                }
            }
            S.num[++S.len] = flag;
            N.itoBig(flag);
            R = R - N * A;
        }
        FOR(i, 1, S.len / 2) swap(S.num[i], S.num[len - i + 1]);
        while(!S.num[S.len] && S.len > 1) S.len--;
        return S;
    }

    BigInt operator % (const BigInt &A) const {
        BigInt S;
        BigInt P = *this / A;
        S = *this - P * A;
        return S;
    }
};
int T;
BigInt N,zero(0);
vector<int> p;
bool vis[maxn];

void init(){
    int n = 1e6;
    for(int i =2;i<n/i;i++){
        if(!vis[i]){
            p.push_back(i);
            for(int j = 2*i;j<n;j+=i){
                vis[j] = true;
            }
        }
    }
}

BigInt gcd(BigInt a,BigInt b){
    return b == zero? a:gcd(b,a%b);
}
int main(){
    init();
    cin>>T;
    while(T--){
        N.read();
        BigInt sum(1),son(1),mu(1);
        for(int i = 0;i<p.size();i++) {
            BigInt pi(p[i]), pi_1(p[i] + 1);
            sum = sum * pi;
            if (sum > N) break;
            son = son * pi_1;
            mu = mu * pi;
        }
        BigInt g = gcd(son,mu);
        son = son/g,mu = mu/g;
        swap(son,mu);
        son.write();putchar('/');mu.write();putchar('\n');

    }
    return 0;
}

ICPC 焦作站I题

I. Distance 【贪心+前缀】

2019-10-20 22 22 41 692
得出结论:
当数轴两端选点数相同时,也就是奇数次选点,选最左端未被选过的点,以让下次偶数选点获得的增值最大。所以奇数选点选未选点最左的一个,偶数选点选未选点最右的一个

#include <iostream>
#include <vector>
using namespace std;
const int maxn = 1e6+10;
typedef long long ll;

ll p[maxn];
ll res[maxn];
int main(){
    int T;cin>>T;
    while(T--){
        int N;cin>>N;
        ll dis;
        for(int i = 2;i<=N;i++){
            scanf("%lld",&dis);
            p[i] = p[i-1]+dis;
        }
        res[1] = 0,res[2] = p[N];//初始化
        int l = 2,r = N-1,idx = 3;//
        int tl = 1,tr  = 1;ll suml = 0,sumr = 0;//左右前缀的数量,左右前缀和
        while(l<=r){
            if(idx%2 == 1){ //奇数选左边端点,偶数选右边
                ll sum = (p[l]-p[1])*tl-suml + (p[N]-p[l])*tr-sumr;
                res[idx] = res[idx-1]+sum;
                tl++,suml+=p[l],l++;
            }else{
                ll sum = (p[r]-p[1])*tl-suml + (p[N]-p[r])*tr-sumr;
                res[idx] = res[idx-1]+sum;
                tr++,sumr+=p[N]-p[r],r--;
            }
            idx++;
        }
        for(int i = 1;i<=N;i++){
            printf("%lld",res[i]);
            if(i!=N)putchar(' ');
        }
        puts("");
    }
    return 0;
}

leetcode 周赛149

1154. 一年中的第几天 【基础题】

先把平年的每月的天数写进数组,计算出天数,之后需要特判一下是否是闰年并且月份>=3,是的话就天数再+1

class Solution {
public:
    int d[13] = {0,31,28,31,30,31,30,31,31,30,31,30,31}; 
    int dayOfYear(string date) {
        int days = 0;
        int year = stoi(date.substr(0,4)); // 讲字串转换成int
        int mouth = stoi(date.substr(5,2));
        int day = stoi(date.substr(8,2));
        if(((year%4 ==0 && year%100!=0) || (year%400 == 0) )&& mouth>=3) days++; //判断闰年+1的情况
        for(int i = 1;i<mouth;i++) days += d[i];
        days += day;
        return days;
    } 
};

1155. 掷骰子的N种方法 【入门dp】

我们定义DP[i][j]: 投了i个骰子,得分为j的方法数
假如f = 3
dp[0][0] = 1
则状态转移方程为:dp[i][j] = dp[i-1][j-1] + dp[i-1][j-2] + dp[i-1][j-3]
用三重循环就可以实现出来

class Solution {
public:
    typedef long long ll;
    const ll mod = 1e9+7;
    ll dp[50][2000];
    int numRollsToTarget(int d, int f, int target) {
        dp[0][0] = 1;
        for(int i = 1;i<=d;i++){
            for(int j = 1;j<=target;j++){
                for(int k = 1;k<=f;k++){
                    if(j-k<0) continue;
                    dp[i][j] = (dp[i][j]+dp[i-1][j-k])%mod;
                }
            }
        }
        return dp[d][target];
    }
};

1156. 单字符重复子串的最大长度 【双指针】

先map记录各字母出现的总次数,然后定义一个L,R 从左到右把数组扫一遍就行了。
以 "aaababa"为例:起点为L = R= 0,R扫到第二个b停止,此时扫过的长度为R-L;
然后 L = R = 第一个b的位置,再继续扫
也就是说,从一个起点开始扫,遇到第一个不等于起点元素的进行跳过,第二次不等于起点元素或者已经扫到数组末尾了就计算此次扫过的长度并更新最大长度。注意如果扫过的元素个数大于map中记录的,需要减一。

class Solution {
public:
    int maxRepOpt1(string text) {
        unordered_map<char,int> mp;
        for(auto c:text) mp[c]++;
        int l = 0,r = 0,newi = 0,len = text.length();
        int res = 0;
        for(int i = 0;i<len;i = newi){
            int tag = 0;
            for(int j = i;j<=len;j++){
                if(j == len || (text[i] != text[j] && tag == 1)){ //扫一次的结束条件
                    int t = j-i;
                    if(t > mp[text[i]]) t--;
                    res = max(res,t);
                    if(j == len) newi = len;//特判
                    break;
                }
                if(text[i]!=text[j] && tag == 0) tag = 1,newi = j; //第一次遇到不等于第一个元素的时候
            }
        }
        return res;
    }
};

leetcode 周赛156

1207. 独一无二的出现次数 [基础]

先基础各个元素出现的次数,然后再对出现的次数进行计数,若有2个以上出现次数相同就为假,否则为真
ps: [-1000,1000] 可以加1000 映射到[0,2000],这样做的原因是数组下标为非负值

class Solution {
public:
    int coun[2500],coun2[2500];
    bool uniqueOccurrences(vector<int>& arr) {
        for(const auto & v:arr) coun[v+1000]++; //元素出现的次数
        for(int i = 0;i<=2000;i++) { 
            if(coun[i] ==0) continue;
            coun2[coun[i]]++; //出现的次数的次数
            if(coun2[coun[i]]>1) return false;
        }
        return true;
    }
};

1208. 尽可能使字符串相等 【双指针】

先假定一个开始坐标L,然后看他最大的结束位置R(剩余可用开销最小);然后重复(L-1,看R是否可以继续向右移动) 。这样就可以遍历完所有剩余可用开销最小的区间

例如: 1 2 3 4,L = 1,R = 4, len = R-L = 3
然后去掉1,剩余可用开销增大|s[1]-t[1]|,然后R看是否能用剩余可用开销继续向右移动

class Solution {
public:
    int equalSubstring(string s, string t, int maxCost) {
        int len = s.length(),res = 0,cur = maxCost;
        int i = 0,j = 0;
        for(;i<len;i++){
            while(j<len){
                if(s[j] == t[j]){ //相等不用开销
                    j++;
                }else if(cur - (int)abs(s[j]-t[j]) < 0){ //剩余可用开销已达到最小
                    break;
                }else{
                    cur -= (int)abs(s[j]-t[j]); 
                    j++;
                }
            }
            res = max(res,j-i);
            cur += (int)abs(s[i]-t[i]);//去掉开头,增加可用开销
        }
        return res;
    }
};

1209. 删除字符串中的所有相邻重复项 II 【栈】

用两个同步的栈,一个记录元素值,一个记录对应元素出现的次数。当栈顶元素出现的次数等于k,两个栈同时pop次数k。
我这题用的数组模拟栈,因为可以进行遍历,比较方便。

class Solution {
public:
    int sk[1000010],coun[1000010],top = -1;
    string removeDuplicates(string s, int k) {
        for(const auto &c:s){
            if(top == -1 || sk[top] != c){
                sk[++top] = c;
                coun[top] = 1;
            }else if(sk[top] == c){
                sk[++top] = c;coun[top] = coun[top-1]+1;
            }
            if(coun[top] == k) for(int i = 1;i<=k;i++) top--;
        }
        string res = "";
        for(int i = 0;i<=top;i++) res+=sk[i];
        return res;
    }
};

1210. 穿过迷宫的最少移动次数 【BFS】

第一次遇见带方向的BFS题,看leetcode题解上有人用的DP,其实差不多的
这题就是在普通的BFS上加了一些特定的移动规则,显得代码特别多,还有一个坑点就是对于一个坐标是可以访问两次的,一个是蛇横向访问,一个是蛇纵向访问。普通的BFS记录步数的数组是dp[x][y],但是这里需要再定义一个方向,dp[x][y][0]表示横向访问(x,y)的步数,dp[x][y][1]表示纵向访问(x,y)的步数

struct node{
    int x,y,st;
};
class Solution {
    public:
    int dp[110][100][2];//0水平 1竖直
    int N;
    vector<vector<int>> G;
    bool judge(int x,int y,int st){
        if(x<0 || x>=N || y<0 || y>=N || dp[x][y][st] != 0 || G[x][y] !=0) return false;
        return true;
    }
    int minimumMoves(vector<vector<int>>& grid) {
        N = grid.size(); G = grid;
        queue<node> q;
        q.push({0,1,0});
        dp[0][1][0] = 0;

        while(q.size()){
            node cur = q.front();q.pop();
            int x,y,st = cur.st;
            //rotate
            if(st == 0){
                x = cur.x+1,y = cur.y-1;
                if(judge(x,y,1) && grid[cur.x+1][cur.y] == 0){
                    q.push({x,y,1});
                    dp[x][y][1] = dp[cur.x][cur.y][st]+1;
                }
            }else{
                x = cur.x-1,y = cur.y+1;
                if(judge(x,y,0) && grid[cur.x][cur.y+1] == 0){
                    q.push({x,y,0});
                    dp[x][y][0] = dp[cur.x][cur.y][st]+1;
                }
            }
            //move
            if(st == 0){
                x = cur.x,y = cur.y+1; // right
                if(judge(x,y,st)){
                    q.push({x,y,st});
                    dp[x][y][st] = dp[cur.x][cur.y][st]+1;
                }
                x = cur.x+1,y = cur.y; //down
                if(judge(x,y,st) && grid[x][y-1] == 0){
                    q.push({x,y,st});
                    dp[x][y][st] = dp[cur.x][cur.y][st]+1;
                }
            }else{
                x = cur.x+1,y = cur.y; //down
                if(judge(x,y,st) ){
                    q.push({x,y,st});
                    dp[x][y][st] = dp[cur.x][cur.y][st]+1;
                }
                x = cur.x,y = cur.y+1; //right
                if(judge(x,y,st)&& grid[x-1][y] == 0){
                    q.push({x,y,st});
                    dp[x][y][st] = dp[cur.x][cur.y][st]+1;
                }
            }
        }
        return dp[N-1][N-1][0] == 0? -1:dp[N-1][N-1][0];
    }
};

leetcode 周赛159

1232. 缀点成线 【gcd】

先任意选两个点求出一个斜率用最简分数a/b来表示,约分需要使用到gcd。然后遍历坐标数组,如果存在两个相邻的元素的斜率c/d不等于a/b就返回false,否则就true
注意所有分数都必须是最简的,0/12最简分数为0/1

class Solution {
public:
    int gcd(int a,int b){
        return !b? a:gcd(b,a%b);
    }
    bool checkStraightLine(vector<vector<int>>& c) {
        int son = c[1][0]-c[0][0],mu = c[1][1]-c[0][1],g = gcd(son,mu);
        son/=g,mu/=g;
        for(int i = 1;i<c.size();i++){
            int s = c[i][0]-c[i-1][0],m = c[i][1]-c[i-1][1],g = gcd(s,m);
            s/=g,m/=g;
            if(s!=son || m!=mu) return false;
        }
        return true;
    }
};

1233. 删除子文件夹 【排序+暴力】

先把字符串的从小到大排序,对于一个字符串,遍历这个字符串,判断他的每一个前缀是否出现过,若出现过就舍弃,若没有就加入到集合中
假如有/a/b已经在集合中了,因为/a/b/c/d的前缀a/b已经在集合中了,所以就舍弃。
/a/b/c/d的前缀有/a,/a/b,/a/b/c

class Solution {
public:
    vector<string> removeSubfolders(vector<string>& f) {
        set<string> st; vector<string> res;
        sort(f.begin(),f.end());
        for(const auto&s:f){
            int exist = 0;
            for(int i = 0;i<s.length();i++){
                if(s[i] == '/' && st.count(s.substr(0,i))){
                    exist = 1;
                    break;
                }
            }
            if(!exist){
                st.insert(s);
                res.push_back(s);
            }
        }   
        return res;
    }
};

1234. 替换子串得到平衡字符串【二分+滑动窗口】

因为答案是一个长度问题,在[0,字符串长度]之间,所以可以尝试用二分来解决,关键是judge函数比较难写,其实也不难,就是一个滑动窗口。
假如已经有一个窗口在字符串中了,窗口**有t个字符,窗口外Q、W、E、R各有a、b、c、d个.设abcd中最大值为m,dif为abcd与m的差值总和,当t>=dif时,此时的窗口大小是可以的,也就是说此次二分的mid是可以替换出来平衡字符串的。
所以我们的目的就了找长度最小的合法窗口,合法窗口指的是可以替换出平衡字符串

class Solution {
public:
    string str;
    unordered_map<char,int> mp;
    bool judge(int n){
        unordered_map<char,int> mp2;
        mp2['Q'] = mp['Q'];mp2['W'] = mp['W'];mp2['E'] = mp['E'];mp2['R'] = mp['R'];

        for(int i = 0;i<n;i++) mp2[str[i]]--;
        int mx = max(max(mp2['Q'],mp2['W']),max(mp2['E'],mp2['R']));
        int dif = 0; for(auto m:mp2) dif+= mx-m.second;
        if(n>=dif) return true;
        for(int i = n;i<str.length();i++){
            mp2[str[i-n]]++;mp2[str[i]]--;
            int mx = max(max(mp2['Q'],mp2['W']),max(mp2['E'],mp2['R']));
            int dif = 0; for(auto m:mp2) dif+= mx-m.second;
            if(n>=dif) return true;
        }
        return false;
    }
    int balancedString(string s) {
        str = s;
        for(auto c:s) mp[c]++;
        int l = 0,r = s.length(),mid;
        while(l<r){
            mid = (l+r)/2;
            if(judge(mid)) r = mid;
            else l = mid+1;
        }
        return l;
    }
};

1235. 规划兼职工作 【dp】

先把开始时间、结束时间、收益装进一个结构体,按照结束时间从小到大排序。
dp[i]表示第i天的收益。假如一个开始时间s,结束时间e,或者收益w,那么可以想到dp[e] = max(dp[e],dp[s]+w) 但是有可能dp[s] = 0,但是dp[t] (t<s) 不为0,所以我们需要用二分查找第最后一个小于等于s的结束时间t,
然后dp[e] = max(dp[e],dp[t]+w)

struct work{
    int s,e,w;
};
bool cmp(const work & n1,const work & n2){
    if(n1.e != n2.e) return n1.e < n2.e;
    return n1.s<n2.s;
}
class Solution {
public:
    int len;
    unordered_map<int,int> dp;
    int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
        len = startTime.size();
        vector<work> node(len);
        for(int i = 0;i<len;i++){
            node[i] = {startTime[i],endTime[i],profit[i]};
        }
        sort(node.begin(),node.end(),cmp);
        sort(endTime.begin(),endTime.end());
        for(int i = 0;i<len;i++){
            if(i>=1) dp[node[i].e] = dp[node[i-1].e];
            int t = upper_bound(endTime.begin(),endTime.end(),node[i].s) - endTime.begin();
            if(--t>=0){
                dp[node[i].e] = max(dp[node[i].e],dp[endTime[t]]+node[i].w);
            }else{
                dp[node[i].e] = max(dp[node[i].e],dp[node[i].s]+node[i].w);
            }
        }
        return dp[endTime[len-1]];
    }
};

ICPC 焦作站A题

A. Xu Xiake in Henan Province

刺裸裸的签到题

#include <iostream>
using namespace std;
 
 
int main(){
    int T;cin>>T;
    while(T--){
        int cur,cnt = 0;
        for(int i = 0;i<4;i++){
            scanf("%d",&cur);
            if(cur>0) cnt++;
        }
        if(cnt == 0) puts("Typically Otaku");
        if(cnt == 1) puts("Eye-opener");
        if(cnt == 2) puts("Young Traveller");
        if(cnt == 3) puts("Excellent Traveller");
        if(cnt == 4) puts("Contemporary Xu Xiake");
    }
    return 0;
}

leetcode 周赛157

1217. 玩筹码 【简单思维】

移动到某个位置偶数步代价为0,奇数步代价为1。所以选定位置时,若选定的是奇数位置,那么代价为所有偶数位置的个数,选定的是偶数位置,那么代价为所有奇数位置的个数。
所有只要记录一下奇数和偶数的个数 ,然后小的那一个就行

class Solution {
public:
    int minCostToMoveChips(vector<int>& chips) {
        int res[2] = {0,0};
        for(auto v:chips) res[v&1]++;
        return min(res[0],res[1]);
    }
};

1218. 最长定差子序列 【入门dp】

从左到右依次遍历,假如当前的元素是x,那么此时更新以x结尾的定差序列 dp[x] = dp[x-dif]+1 (dif 为定差)。在更新过程中不断的取max就行,然后返回max。这个dp的存储可以用unordered_map来存。

class Solution {
public:
    int longestSubsequence(vector<int>& arr, int difference) {
        unordered_map<int,int> mp; 
        int res = 0,dif = difference;
        for(const auto& v:arr){
            mp[v] = mp[v-dif]+1;
            res = max(mp[v],res);
        }
        return res;
    }
};

1219. 黄金矿工 【入门DFS】

遍历整个面板,对于一个不为0的位置开始DFS,DFS过程中需要加入访问标记+回溯,因为题目中移动过程中不可以回头。

class Solution {
public:
    bool vis[100][100];
    int dir[4][2] = {-1,0,0,-1,1,0,0,1};
    int N,M,res = 0;
    vector<vector<int>> grid2;
    int getMaximumGold(vector<vector<int>>& grid) {
        N = grid.size(),M = grid[0].size();  grid2 = grid;
        for(int i  = 0;i<grid.size();i++){
            for(int j = 0;j<grid[i].size();j++){
                if(grid[i][j] != 0){
                    vis[i][j] = 1;
                    DFS(i,j,grid[i][j]);
                    vis[i][j] = 0;
                }
            }
        }
        return res;
    }
    void DFS(int i,int j,int cur){
        res = max(res,cur);
        for(int d = 0;d<4;d++){
            int x = i+dir[d][0],y = j+dir[d][1];
            if(x<0 || x>=N  || y<0 || y>=M || vis[x][y] == 1 || grid2[x][y] == 0) continue;
            vis[x][y]= 1; 
            DFS(x,y,cur+grid2[x][y]);
            vis[x][y]= 0;
        }
    }
};

1220. 统计元音字母序列的数目【入门DP】

和第2题一样,需要知道每个字母可以接在什么字母后面。
例如a可以接在i和u后面,更加一个长度,以a结尾的字符串就等于上长度以e,i,u结尾的个数总和
a: e,i,u e: a,i i: e,o o: i u: i,o

class Solution {
public:
    const int mod = 1e9+7;
    int countVowelPermutation(int n) {
        long long dp[5],f[5],res =0;
        for(int i = 0;i<5;i++) dp[i] = 1;//n==1 的时候
        while(--n){
            f[0] = (dp[1]+dp[2]+dp[4])%mod; //更新dp值
            f[1] = (dp[0]+dp[2])%mod;
            f[2] = (dp[1]+dp[3])%mod;
            f[3] = (dp[2])%mod;
            f[4] = (dp[2]+dp[3])%mod;
            for(int i = 0;i<5;i++) dp[i] = f[i];//拷贝回去
        }
        for(int i = 0;i<5;i++) res = (res+dp[i])%mod;//计算总和
        return res;
    }
};

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.