2021牛客寒假算法基础集训营6

回文括号序列计数

https://ac.nowcoder.com/acm/contest/9986/A

A、回文括号序列计数

既要是回文又要是括号序列,我们知道回文具有对称性,但是我们写一个回文串就会发现
类似这种回文串不可能是括号序列,所以只有在的时候存在一个空串,特殊判断即可。

#include <bits/stdc++.h>
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
#define all(__vv__) (__vv__).begin(), (__vv__).end()
#define endl "\n"
#define pai pair<int, int>
#define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__))
#define rep(i, sta, en) for(int i=sta; i<=en; ++i)
#define repp(i, sta, en) for(int i=sta; i>=en; --i)
typedef long long ll; typedef unsigned long long ull; typedef long double ld;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar())    s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; }
inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op)    putchar(op); return; }    char F[40]; ll tmp = x > 0 ? x : -x;    if (x < 0)putchar('-');    int cnt = 0;    while (tmp > 0) { F[cnt++] = tmp % 10 + '0';        tmp /= 10; }    while (cnt > 0)putchar(F[--cnt]);    if (op)    putchar(op); }
inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
ll qpow(ll a, ll b) { ll ans = 1;    while (b) { if (b & 1)    ans *= a;        b >>= 1;        a *= a; }    return ans; }    ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; }
const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} };
const int MOD = 1e9 + 7;
const int INF = 0x3f3f3f3f;
struct Node {
    ll val;
    int id;
    bool operator < (const Node& opt) const {
        return val < opt.val;
    }
};

const int N = 1e6 + 7;
ll n, m;
ll p[N];
void solve() {
    n = read();
    if (!n)    print(1);
    else print(0);
}

int main() {
    int T = read();    while (T--)
        solve();
    return 0;
}

B、系数

发现答案可对3取模,又是,我们知道多项式的系数和排列组合有关,所以这个量级使用可以解决组合数问题。剩下的关键就是找到应该求解的组合数式子。
我们观察里面每一项模3,考虑一个转化。把看成,这样在每次挑选幂次的时候还是按照的幂次依次从括号中选取,但是这样在选中1次幂的时候,会选择,当它和别的项累乘时,你会发现它等于,显然后面的一项会等于0,那么也就是说明在求解系数的时候是等价的。
我们就可以把式子变化为。这个式子的系数求解就很简单了吧。

,还要注意一下我们虽然说等价,但是前面式子可能求解出负数,当求解到负数的时候就加个3变成整数即可。时间复杂度

#include <bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
#define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0)
typedef long long ll;
inline ll read() { ll s = 0, w = 1; char ch = getchar(); while (ch < 48 || ch > 57) { if (ch == '-') w = -1; ch = getchar(); }    while (ch >= 48 && ch <= 57) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();    return s * w; }

// 模数p较小打表 并且前提p是素数
//const int N = 1e5 + 10;
//ll fac[N];//阶乘打表
//void init(ll p) {//此处的p应该小于1e5,这样Lucas定理才适用
//    fac[0] = 1;
//    for (int i = 1; i <= p; i++)
//        fac[i] = fac[i - 1] * i % p;
//}

// 模数p较大直接计算组合数
ll qpow(ll a, ll b, ll m) { //非质数也要用快速幂
    ll ans = 1;
    a %= m;
    while (b) {
        if (b & 1)ans = (ans % m) * (a % m) % m;
        b /= 2;
        a = (a % m) * (a % m) % m;
    }
    ans %= m;
    return ans;
}
ll inv(ll x, ll p) {//x关于p的逆元,p为素数
    return qpow(x, p - 2, p);
}

// p较小情况
//ll C(ll n, ll m, ll p){//组合数C(n, m) % p
//    if (m > n)return 0;
//    return fac[n] * inv(fac[m] * fac[n - m], p) % p;
//}

ll C(ll n, ll m, ll p) {//组合数C(n, m) % p
    if (m > n)return 0;
    ll up = 1, down = 1;//分子分母;
    for (int i = n - m + 1; i <= n; i++)up = up * i % p;
    for (int i = 1; i <= m; i++)down = down * i % p;
    return up * inv(down, p) % p;
}
ll lucas(ll n, ll m, ll p) {
    if (m == 0)return 1;
    return C(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}

int main() {
    int T = read();
    while (T--) {
        ll n = read(), k = read();
        int ans = lucas(2 * n, k, 3);
        if (k & 1)    ans = (3 - ans) % 3;
        printf("%d\n", ans);
    }
    return 0;
}

C、末三位

可以找规律,也可以直接快速幂,规律就按照奇偶分类就行。

void solve() {
    while (~scanf("%lld", &n)) {
        int ans = qpow(5, n, MOD);
        printf("%03d\n", ans);
    }
}

D、划数

最后剩下的一个数一定是,所以这个数一定没有处理过,也就是表明其他数都被算过了,直接求合算一下即可。注意特判的情况。

const int N = 1e6 + 7;
ll n, m;
ll p[N];
void solve() {
    int m = read();
    bool flag = 1;
    rep(i, 1, n) {
        p[i] = read();
        if (p[i] == m and flag)
            p[i] = 0, flag = 0;
    }
    if (n == 2) {
        int ans = max(p[1], p[2]);
        print(ans);
        return;
    }
    rep(i, 1, n) {
        p[i] = (p[i] + p[i - 1]) % 11;
    }
    print(p[n]);
}

E、网格

每一个格点只能在左右选一个方向,也只能在上下选一个方向,那么可以看出他们对于选择是独立的。我们分行列处理。
我们处理行的时候,使用数组,代表当前行的第列的方向选择是往左还是往右,那么知道当前行的第一个点只能选择往右,第二个点可以选择往右也可以选择往左,在第三个点开始往后就有明显的转移规律了。


处理完列之后,把行一样的按照选择方向的上下处理,预处理每个数的一的数量可以把时间复杂度做到

const int N = 1e3 + 7;
ll n, m;
int cnt[N * 3];
int a[N][N], f[N][2];

// f[i][0/1] 代表某一行中第i列数往左(0)往右(1)选择的最大值
// 同理用在行中计算时往上是(0)往下是(1)

int calc(int x) { return x + cnt[x]; }

void solve() {
    rep(i, 1, 3000)    cnt[i] = cnt[i & (i - 1)] + 1;
    n = read(), m = read();
    rep(i, 1, n)
        rep(j, 1, m)    a[i][j] = read();
    ll ans = 0;
    rep(i, 1, n) {
        f[2][0] = calc(a[i][1] ^ a[i][2]); // 第二个数只能往左才会产生贡献
        f[2][1] = 0;
        rep(j, 3, m) {
            f[j][0] = max(f[j - 1][0], f[j - 1][1] + calc(a[i][j] ^ a[i][j - 1]));
            f[j][1] = max(f[j - 1][0], f[j - 1][1]);
        }
        ans += max(f[m][0], f[m][1]);
    }
    rep(j, 1, m) {
        f[2][0] = calc(a[1][j] ^ a[2][j]); // 第二个数只能往上才会有贡献
        f[2][1] = 0;
        rep(i, 3, n) {
            f[i][0] = max(f[i - 1][0], f[i - 1][1] + calc(a[i][j] ^ a[i - 1][j]));
            f[i][1] = max(f[i - 1][0], f[i - 1][1]);
        }
        ans += max(f[n][0], f[n][1]);
    }
    print(ans);
}

F、组合数问题

正解使用的是复数的快速幂,因为本人暂时没看到他如何转换的,所以就不多介绍了 赛中我解题的方法是暴力找出前

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

2021牛客寒假算法基础集训营 文章被收录于专栏

2021牛客寒假夏令营题解

全部评论

相关推荐

ros275229:社团删了吧,cf因该1200才勉强入门吧,也删了,你可以写算法刷了多少道,都比这个好
点赞 评论 收藏
分享
2025-12-02 02:15
门头沟学院
最近菊厂陆续开了,极力劝退那些拿13级的985硕士,就13级那么点儿薪资,一线城市每个月到手1.8/7/6w,租房2k还是破烂,吃饭2k还是预制菜,买个1k衣服都是聚酯纤维破塑料,稍微出去浪一浪,能留1w就是万岁,要是再有个啥都想买的对象,一线工作一年难存10w。隔壁工地混泥土,钳工,焊工一天800+,还包吃包住。读书18年到985硕士出来就为了进厂螺丝工?还不如从8岁童工开始干活,别人读书完了你工龄18+,混不上领导也是个小头头了。当然专科进来正式工,od都行,一般本科进来13级也OK,毕竟22岁年纪摆在那个地方还不需要太花钱。读硕博的基本26岁,工作两年就要结婚的,兜里没几个崽,连彩礼都要信用贷。菊厂离职的不少,毕竟正常没人受得了9116(梗:再来一次911刷6)。为啥这时候劝?因为刚下班,因为国考刚完,省考下周,就是可惜选调只有当年应届能报。现在回想能拍断大腿。应届生真实好身份,错过这一次,选调,考公,考编,当老师,进医院,研究所,高校,央国企,基本都无缘了,就连报名资格都被剥夺了,可谓是被党和国家遗弃的废材,统称“社会上的”,扔到社会去流浪,被用坏了就扔医院,长期超负载使用,零件修不好基本可以扔火里回炉重造了。体制内奉行找体制内的,都是党和国家选的人才,智力不差,样貌不丑,身材端正,收入稳定,安居房政策福利待遇也OK。因公出行都是报销,周末顺带“游山玩水“,这种体制内单身资源但凡想找对象,去社会上随便吆喝一声都排队。观察一下,基本没什么公务员在相亲,因为早就被邻里邻居抢光了。
哈哈哈,你是老六:就这不去的人大把人干呢,现在不缺人干活,你不干大把干呢,还有那个说农民工赚钱的,那个800+我估计肯定也就那一段时间,哪有这么赚钱,还是一句话,要想存下钱必须花销极低,能省的就不花钱,工资要高点
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务