牛客练习赛53 A-E
牛客联系赛53 A-E
题目链接:Link
A 超越学姐爱字符串
题意: 长度为N的字符串,只能有C,Y字符,且字符串中不能连续出现 C。
思路: 其实就是DP,\(Dp[i][c]\) 表示长度为 \(i\) , 以 \(C\) 结尾的字符串有多少种。那么整个状态方程就有:
会发现其实就是斐波那契数列而已。
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}}$ 简单暴力的题意。。。
思路:这题就是找规律。。。把具体计算式写出来,就发现规律了。具体如下:
第一列即为 \(\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;
}