3.24字节笔试题解

分享题解攒人品

(写题能力严重退化~

第一题

题意:凸多边形有n条边,每条边上ai个标记,问选三个标记组成三角形的方案数,对1e9+7取模(n<=1e5, ai <=1e9)

思路:dp

dp[i][j]表示前i条边取了j个标记,有转移式

dp[i][j+k] += dp[i-1][j] + C(ai, k) 第i条边取了k个标记。

由于j不超过3,k不超过2,且C(ai, k)可以直接乘除得到,复杂度O(n)

看到有大佬容斥思路做的,很妙,没想到哈哈哈。

第二题

题意: 给定一个字符串,求包含"byte"或者"dance"的子串数量(字符串长度不超过1e5)

思路:数数

先求出所有byte,dance子串的位置,我们记为一个区间[l,r],我们知道既然byte是个合法串,那么[l,r]区间往左往右延伸都是合法的。

然后就是怎么不重复计数了。我们对区间[l,r]按照l排序,从左往右扫,每个区间贡献是(l - last_l) * (n -1 - r + 1),其中last_l表示上个区间的左端点,n表示字符串总长。只要保持当前区间的左端点,不超过上个区间左端点就不会重复计数。复杂度O(n)

第三题

题意: 给n个二元组,每个二元组<u,v>表示v个u,比如<1,3>表示1 1 1。然后q次询问,每次问区间[l, r]和。(n<=1e5,u,v<=1e9)

思路:前缀和,二分,数数

对u和v分别做前缀和,u的前缀和sum数组,v的前缀和cnt数组。

对于询问[l,r]我们先在cnt数组中用lower_bound或者二分找到对应的下标pl和pr

答案则为sum[pr-1] - sum[pl] + (cnt[pl] - l + 1) * 对应的u + (r - cnt[pr-1] ) * 对应的u,复杂度O(n + qlogn)

怎么理解呢,把[pl,pr]拆成[pl+1, pr - 1] 还有pl和pr单独两个点算贡献。[pl+1, pr - 1]区间肯定是吃满每个数和数量的贡献,这里用前缀和算下就可以。pl和pr单独两个点就要看多出或者缺少多少个数组,然后乘上对应的u,这里说的有点抽象。。。

贴个代码吧

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int mod = 1e9 + 7;
const int N = 1e5 + 10;;
int n, q;
int sum[N], cnt[N];
array<int, 2> E[N];
signed main() {
    cin >>n;
    for(int i = 1; i <=n; i++){
        int u, v;cin >> u >> v;
        E[i] = {u, v};
        cnt[i] = (cnt[i-1] + v);
        sum[i] = (sum[i-1] + u * v % mod) % mod;
    }
    cin >> q;
    while(q--){
        int l, r;
        cin >> l >> r;
        int pl = lower_bound(cnt+1, cnt+1+n, l) - cnt;
        int pr = lower_bound(cnt+1, cnt+1+n, r) - cnt;
        int ans = (pr - 1 >= pl + 1 ? (sum[pr-1] - sum[pl] + mod) % mod : 0);
        if(pl==pr){
            ans += (r - l  + 1) * E[pl][0] % mod;
            ans %= mod;
        }else {
            ans += (cnt[pl] - l  + 1 + mod) % mod * E[pl][0] % mod; 
            ans %= mod;
            ans += (r - cnt[pr-1] + mod) * E[pr][0] % mod;
            ans %= mod;
        }
        cout << ans << endl;
    }
}

第四题

题意: 给01矩阵,行不超过5,列不超过1000。其中有些位置是问号'?'。现在要把'?'变成01,不能出现相邻的1,问合法方案数,对1e9+7取模。

思路:dp,状压

由于就5行,2^5也就32。

dp很容易想dp[i][s],表示第i列的字符串状态为s,s即二进制状压。

if(i列和i-1列没有相邻1) , 有转移dp[i][s] += dp[i-1][k],复杂度O(4 ^n * m)

代码是难写点。凭回忆写了下大概。

这里状压有个特殊之处,就是01已知的地方就用已知的数表示即可,比如某列式01?(我把列横过来),的状态压缩是010或者011。所以下面我在check函数中首先会去check这个状态的合法性(代码11到14行)。

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
const int mod = 1e9 + 7;
const int N = 1e5 + 10;;
int n, m;
int dp[1010][31];
string s[10];
bool check(int col, int col_state, int last_col_state){
    for(int i = 0; i < n; i++){
        if(s[i][col] != '?' && ((col_state>>i&1) != s[i][col] - '0')){
            return false;
        }
    }
    for(int i = 0; i < n; i++){
        int k = s[i][col] == '?' ? col_state>>i&1 : s[i][col] - '0';
        if(k){
            // 与上一行进行check
            int last_col_k = col_state>>(i-1)&1;
            if(last_col_k){
                return false;
            }
        }
    }
    // 与前一列check
    // 第一列无需与上一列check
    if(col){
        for(int i = 0; i < n; i++){
            int k = s[i][col] == '?' ? col_state>>i&1 : s[i][col] - '0';
            int last_col_k = last_col_state>>i&1;
            if(k == 1 && k == last_col_k){
                return false;
            }
        }
    }
    return true;
}
signed main() {
    cin >> n >> m;
    for(int i = 0; i < n; i++){
        cin >> s[i];
    }
    for(int i = 0; i < m; i++){
        for(int j = 0; j < (1<<n); j++){
            if(i){
                for(int k = 0; k < (1<<n); k++){
                    if(dp[i - 1][k] && check(i, j, k)){
                        dp[i][j] = (dp[i][j] + dp[i - 1][k]) % mod;
                    }
                }
            }
            else {
                if(check(i, j, -1)){
                    dp[i][j]++;
                }
            }
        }
    }
    int ans = 0;
    for(int i = 0; i < (1<<n) ; i++){
        ans = (ans + dp[m-1][i])%mod;
    }
    cout << ans;
}

全部评论
向妙酱学习
1 回复 分享
发布于 03-25 09:17 上海
update 简历评估挂了😀
1 回复 分享
发布于 04-10 21:53 广东
感谢,向佬学习
点赞 回复 分享
发布于 03-24 12:05 美国
没收到笔试
点赞 回复 分享
发布于 03-24 15:02 广东
佬太强了
点赞 回复 分享
发布于 03-24 18:26 浙江
没收到笔试
点赞 回复 分享
发布于 03-25 10:57 广东
大佬还继续春招嘛
点赞 回复 分享
发布于 03-25 10:57 广东

相关推荐

喜欢走神的孤勇者练习时长两年半:池是池,发是发,我曾池,我现黑
点赞 评论 收藏
分享
10-15 16:27
门头沟学院 C++
LeoMoon:建议问一下是不是你给他付钱😅😅
点赞 评论 收藏
分享
评论
4
9
分享
牛客网
牛客企业服务