近期太忙了,好多AK的笔试都没发出来,今天做了个网易,感觉难度挺大的,和uu们分享一下

T1 (100%)

购买物品,可以在A超市买,也可以在B超市买,B超市限制只能买连续的一段。 最大子串问题。


        int[] sub = new int[n];
        for(int i = 0; i < n; i++){
            sub[i] = a[i] - b[i];
        }

        int l = 0, r = 0;// 选l不选r
        int cl = 0, cr = 0;
        long ans = 0, cur = 0;

        for(int i = 0; i < n; i++){
            if(cur + sub[i] > 0){
                cur += sub[i];
                cr = i+1;
            }else{
                cur = 0;
                cl = i+1;
            }
            if(ans < cur){
                ans = cur;
                l = cl;
                r = cr;
            }
        }
        long res = suma;
        for(int i = l; i < r; i++){
            res -= a[i];
            res += b[i];
        }


T2 (100%)

最少的跳跃次数。 做最少次的公交车。


        Arrays.sort(c, 
        (int[] a, int[] b)->{return a[0] == b[0] ? a[1] - b[1] : a[0] - b[0] ;});
        int ind = 0, res = 0, tag = 0;
        PriorityQueue<Integer> q = 
        new PriorityQueue<Integer>((a, b)->{return b-a;});
        if(x == y){
            System.out.println(0);
        }else if(c[0][0] > x) {
            System.out.println(-1);
        }else{
            while(ind < m){
                while(ind < m && c[ind][0] <= x){
                    q.add(c[ind++][1]);
                }
                if(q.isEmpty() || q.peek() == x){
                    break;
                }
                x = q.peek();
                res++;
                if(x >= y) break;
            }
            if(x < y) System.out.println(-1);
            else System.out.println(res);
        }

T3(100%)

连线问题,咋都是源。。。


        int[][] dp = new int[na+1][nb+1];
        for(int i = 1; i <= na; i++){
            for(int j = 1; j <= nb; j++){
                dp[i][j] = Math.max(dp[i-1][j], dp[i][j-1]);
                if(a[i-1] == b[j-1]){
                    dp[i][j] = Math.max(dp[i][j], dp[i-1][j-1]+1);
                }
            }
        }

T4 (100%)

这题有意思了,花了我40分钟左右。

有n行m列的人,分三组,前后左右相邻人不在同一组。

n <= 5, m <= 1000, 共三组。

看范围,暴力肯定TLE,又懒得写dp,只能dfs + cache的亚子试试。

cache的key如何设置?

取决于影响当前以及后续操作的因素。首先是从上往下,从左往右,依次填人,那么影响当前位置的就是上面的人和左面的人。我们记录状态,但是下一次又是左面下面的人,所以要记录一整列的分组状态,其次还要记录当前填到那里了。

所以就是 5个1-3的数字,一个1-5的row,一个1-1000的col。

状态压缩刚刚好够用,所以这个数据范围是精心设计的。

用ll,大致:row + col + tag(tag是10位bit)

然后有趣的是,我们左侧和上方的人刚好是第一个和最后一个tag的bit部分,就用起来很方便了。

贴一些核心代码:


void findChu(int ctal, int cur, ll ctag){ // 先枚举第一列
    if(cur == ctal) {
        chu.push_back(ctag);
        return ;
    }
    for(int i = 1; i <= 3; i++){
        if(i != (ctag % 4)) findChu(ctal, cur + 1, (ctag << 2) | i);
    }
}

int findRow(ll tag){return (7 & (tag >> 28));}
int findCnt(ll tag){return (((1 << 10) - 1) & (tag >> 16));}

bool check(int ci, ll tag){ // 检查能不能放
    int crow = findRow(tag), ccnt = findCnt(tag);
    if(crow == 0){
        int xi = (3 & (tag >> (2 * (row - 1))));
        if(ci != xi) return true;
        else return false;
    }else{
        int xi1 = (3 & tag);
        int xi2 = (3 & (tag >> (2 * (row - 1))));
        if(ci != xi1 && ci != xi2) return true;
        else return false;
    }
}

ll dfs(ll tag){
    if(mp.find(tag) != mp.end()) return mp[tag];
    ll ans = 0;
    int crow = findRow(tag), ccnt = findCnt(tag);
    if(crow == 0 && ccnt == cnt - 1) return 1;//填满
    int nrow = (crow == (row - 1)) ? 0 : crow + 1;
    int ncnt = (crow == (row - 1)) ? ccnt + 1 : ccnt;
    for(int i = 1; i <= 3; i++){
        if(check(i, tag)) {
            ll ntag = ((ll) nrow << 28) | ((ll) ncnt << 16) | 
            (((tag << 2) | i) & ((1 << (2 * row)) - 1));
            ans = (ans + dfs(ntag)) % mod;
        }
    }
    return mp[tag] = ans;
}

int main() {
    cin >> row >> cnt;
    findChu(row, 0, 0);
    for(int i = 0; i < chu.size(); i++) res = (res + dfs(chu[i])) % mod;
    cout << res;
    return 0;
}