牛客练习赛53 A-E

牛客联系赛53 A-E

题目链接:Link

A 超越学姐爱字符串

题意: 长度为N的字符串,只能有C,Y字符,且字符串中不能连续出现 C。

思路: 其实就是DP,\(Dp[i][c]\) 表示长度为 \(i\) , 以 \(C\) 结尾的字符串有多少种。那么整个状态方程就有:

\[DP[i][c] = Dp[i-1][y]\\ Dp[i][y] = Dp[i-1][c] + Dp[i-1][y] \]

会发现其实就是斐波那契数列而已。

Code

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const ULL MOD = 1000000000 + 7;
const int maxn = 100000 + 13;
ULL Dp[maxn][2];

void Init() {
    // 0 --> Y, 1 ---> C
    memset(Dp, 0, sizeof(Dp));
    Dp[0][0] = Dp[0][1] = 0;
    Dp[1][0] = Dp[1][1] = 1;
    for(int i = 2; i < maxn; ++i) {
        Dp[i][0] = (Dp[i-1][0] + Dp[i-1][1]) % MOD;
        Dp[i][1] = Dp[i-1][0];
    }
}

int main() {
    
    Init();
    int n;
    while(scanf("%d", &n) != EOF) {
        ULL sum = (Dp[n][0] + Dp[n][1]) % MOD;
        printf("%lld\n", sum);
    }
    return 0;
}

B 美味果冻

题意: $ \sum_{i=1}{n}\sum_{j=1} {i * [\frac{i}{j}]^{j}}$ 简单暴力的题意。。。

思路:这题就是找规律。。。把具体计算式写出来,就发现规律了。具体如下:

\[\begin{align} &1 \\ &2^2 \ \ 2*1^2 \\ &3^2 \ \ 3*1^2 \ \ 3*1^3 \\ &4^2 \ \ 4*2^2 \ \ 4*1^3 \ \ 4*1^4\\ &\cdots \\ &n^2 \ \ n*[\frac{n}{2}]^2 \ \ n*[\frac{n}{3}]^3 \cdots n*1^n \end{align} \]

第一列即为 \(\sum_i^n i^2\) ,第\(J\)列开始,就是以 \([\frac{n}{j}]\) 分块了。

Code:

int main() {
    false_stdio;
    cin >> n;
    for (ll j = 1; j <= n; j++) {
        num[j] = j;
        ans = (ans + j * j % mod) % mod;
    }
    for (ll j = 2; j <= n; j++) {
        cnt = n / j;
        ll L = j;
        for (int i = 1; i < cnt; i++) {
            tot = (L * j + (j * (j - 1) >>1)) % mod;
            num[i] = num[i] * i % mod;
            ans = ans + tot * num[i] % mod;
            L += j;
        }
        num[cnt] = num[cnt] * cnt % mod;
        tot = (n - cnt * j + 1) % mod;
        ans =ans+ (L * tot % mod + (tot * (tot - 1)>>1)) % mod * num[cnt] % mod;
 
    }
    ans = (ans + mod) % mod;
    cout << ans << endl;
    return 0;
}

C 富豪凯匹配串

题意:0-1 字符串匹配, '_' 代表通配符,输出有多少是成功匹配的。

思路:因为是 0-1 字符串,所以是可以使用 bitset 来做这题的。按与操作来匹配相应位是否相等即可。

Code

int cnt = 0;
bitset<1005> p;
bitset<1005> q;
cin >> str;
for(int j = 0; j < m; ++j) {
   char c = str[j];
   if(c == '0') {
      q[j] = 0; p[j] = 1;
   } else if(c == '1') {
      p[j] = q[j] = 1;
   } else if(c == '_') {
      p[j] = q[j] = 0;
   }
}
for(int i = 0; i < n; ++i) {
   if((p&Str[i]) == q) cnt ++;
}
cout << cnt << endl;

D 德育分博弈政治课

题意:给你 \(N\) 个骰子, 每个骰子的面是给定的 1-9 中的 6个数字, 然后 \(Q\) 次询问,每次询问是一个长串字符串 \(str\) ,只含有 1 - 9 字符,问你的 \(N\) 个骰子, 骰子朝上的面记录为 \(c\) , 问可不可以用你的 \(N\) 个骰子选 \(L\) 个, 排列,使得 \(c_1c_2 \cdots c_l = str\)

思路:主要是总共只有 9 个字符,也就是说所有的状态只有 $2^9 $ 种状态。。。 可以状态压缩 + 暴力搜索状态。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1024;
int cnt[maxn];
int num[maxn];
// 离散化状态, 方便计数, 暴力搜索状态
int main() {
    memset(cnt, 0, sizeof(cnt));
    memset(num, 0, sizeof(num));
    int n, Q;
    string str;
    cin >> n >> Q;
    //处理状态
    for(int i = 0; i < n; ++i) {
        cin >> str;
        int len = str.length();
        int status = 0;
        for(int j = 0; j < 6; ++j) {
            status |= 1<<(str[j]-'1');
        }
        cnt[status]++;
    }
    //统计 只要串里面有一个相同的,就可以纳入状态 2^9
    for(int i = 0; i < 512; ++i) {
        for(int j = 0; j < 512; ++j) {
            if(i&j) num[i] += cnt[j];
        }
    }
    
    for(int q = 0; q < Q; ++q) {
        cin >> str;
        int len = str.length();
        bool jug = true;
        int cnums[10] = {};
        //memset(cnums, 0, sizeof(cnums));
        for(int i = 0; i < len; ++i) cnums[str[i]-'1']++;
        for(int i = 0; i < 512 && jug; ++i) {
            int needNums = 0;
            for(int j = 0; j < 9; ++j) {
                if((i>>j) & 1) {
                    needNums += cnums[j];
                }
            }
            if(needNums > num[i]) jug = false;
        }
        //cout << jug << endl;
        string res = (jug ? "dyf" : "zzk");
        cout << res << endl;
    }
    
    return 0;
}

老瞎眼 pk 小鲜肉

题意: 给一个数组 \(Num\) ,给 一组区间查询 \([L_i, R_i]\) , 使得有区间最短的 \([l_i, r_i]\)\(L_i < l_i < r_i < R_i\) 下,有\(Num[l_i] \oplus Num[l_{i+1}]\oplus \cdots \oplus Num[r_i] = 0\)

思路: 首先最容易想到的就是前缀和,但是,根据题目数据,又明显会超时。区间,不难想到会要结合一下线段树来做。问题是如何用线段树来优化。

​ 首先,不考虑区间,考虑全部数组,如何得到最短 的区间。显然就是顺序处理前缀和,遇到相等的,记录下来(Tips:\(a \oplus a = 0\))。对于这道题来说,可以先预处理,把每一对这样相等的,距离最短的记录下来,然后离线处理所有询问 , 用线段树维护当前询问,最大右端为 \(r_i\) 情况下,所能获得的最区间值。

#include <bits/stdc++.h>
using namespace std;
#define lson l, mid, rt << 1
#define rson mid+1, r, rt<<1|1
#define IOSPEED ios::sync_with_stdio(false); cin.tie(0); 
const int maxn = 500000 + 13;
const int INF = 0x7ffffffa;
int minDis[maxn<<2];
int Nums[maxn], pre[maxn], pos[maxn<<2];

void PushUp(int rt) {
    minDis[rt] = min(minDis[rt<<1],minDis[rt<<1|1]);
}

void Build(int l, int r, int rt) {
    minDis[rt] = INF;
    int mid = (l + r) >> 1;
    Build(lson);
    Build(rson);
}

void Update(int pos, int val, int l, int r, int rt) {
    if(l == r) {
        minDis[rt] = min(val, minDis[rt]);
        return ;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) Update(pos, val, lson);
    else Update(pos, val, rson);
    PushUp(rt);
}

int Query(int L, int R, int l, int r, int rt) {
    if(L <= l && r <= R) {
        return minDis[rt];
    }
    int mid = (l + r) >> 1;
    int resMin = INF;
    if(L <= mid) resMin = min(resMin, Query(L, R, lson));
    if(R > mid) resMin = min(resMin, Query(L, R, rson));
    return resMin;
}

struct QuesNode {
    int l, r, id;
    bool operator < (const QuesNode& a) {
        return r < a.r;
    }
};

QuesNode q[maxn];
int ans[maxn];
int n, Q;
int main() {
    IOSPEED;
    cin >> n >> Q;
    for(int i = 1; i <= n; ++i) {
        cin >> Nums[i];
    }
    fill(begin(minDis), end(minDis), INF);
    fill(begin(pre), end(pre), -1);
    fill(begin(ans), end(ans), INF);
    fill(begin(pos), end(pos), -1);
    int sum = 0;
    pos[0] = 0;
    // 第 i 个数的最短区间为 i - pre[i] + 1
    for(int i = 1; i <= n; ++i) {
        sum = sum ^ Nums[i];
        if(pos[sum] != -1) {
            pre[i] = pos[sum]+1;
        } else pre[i] = -1;
        pos[sum] = i;
    }
    for(int i = 0; i < Q; ++i) {
        cin >> q[i].l >> q[i].r;
        q[i].id = i;
    }
    sort(q, q+Q);
    int pos = 0;
    for(int i = 1; i <= n; ++i) {
        if(pre[i] != -1) Update(pre[i], i-pre[i]+1, 1, n, 1);
        while(q[pos].r == i) {
            ans[q[pos].id] = Query(q[pos].l, q[pos].r, 1, n, 1);
            pos++;
        } 
    }
    for(int i = 0; i < Q; ++i) {
        cout << (ans[i]==INF ? -1 : ans[i]) << endl;
    }
    return 0;
}
posted @ 2019-10-13 13:39  LiverProudmoore  阅读(407)  评论(0编辑  收藏  举报