首页 > 其他分享 >CF1997(edu168)题解 A-F

CF1997(edu168)题解 A-F

时间:2024-07-31 11:55:35浏览次数:14  
标签:return int 题解 CF1997 edu168 long cin ans mid

A. Strong Password

注意到最大效果是在两个相同字符之间插入一个不同的,贡献为 3。

否则在一开始插入一个和首位不同的,贡献为 2。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

void solve()
{
    string s; cin >> s;
    bool ok = 0;
    for(int i = 0; i < s.size() - 1; i ++)
    {
        if(s[i] == s[i + 1])
        {
            ok = 1;
            cout << s.substr(0, i + 1) + (char)((s[i] - 'a' + 1) % 26 + 'a') + s.substr(i + 1) << "\n";
            break;
        }
    }
    if(!ok) cout << (char)((s[0] - 'a' + 1) % 26 + 'a') << s << "\n";
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t;cin >> t;while(t --) solve();

    return 0;
}

B. Make Three Regions

注意到如果要分割成三部分,那么这一块的三面一定都要是 .

设新堵上的块为 o,图应该长这样:

.o.
?.?

因为三块不连通,所以 ? 应该是 x

所以

图应该长这样(两种):

.o. | x.x
x.x | .o.

因为保证原图联通,所以直接判断有几个像这样的图形就行了。

C. Even Positions

直接考虑贪心填右括号,不用担心右括号填多了出现 (())))(( 的情况。

因为最差也可在每个右括号前补一个左括号(奇数位都可以自己选择)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 2e5 + 5;

void solve()
{
    int n; string s; cin >> n >> s;
    int ans = 0;
    stack<int> stk;
    for(int i = 0; i < s.size(); i ++)
        if(stk.size() && s[i] != '(') ans += i - stk.top(), stk.pop();
        else stk.push(i);
    cout << ans << "\n";
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t;cin >> t;while(t --) solve();

    return 0;
}

上面用栈维护左括号位置,还可以拆贡献,只要维护未配对左括号个数即可。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 2e5 + 5;

void solve()
{
    int n; string s; cin >> n >> s;
    int ans = 0;
    int c = 0;
    for(int i = 0; i < s.size(); i ++)
    {
        if(c && s[i] != '(') c --;
        else c ++;
        ans += c;
    }
    cout << ans << "\n";
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t;cin >> t;while(t --) solve();

    return 0;
}

D. Maximize the Root

因为节点 \(u\) 做操作不会影响父节点,所以可以 dp,设 \(f(u)\) 表示 \(u\) 子树内最小值最大是多少。

设 \(g(u)=\min_{v\in sons(u)}f(v)\)

有 \(f(u)=\min(a_u,g(u))\)。

注意到当 \(a_u<g(u)\) 时, \(a_u\) 成为 \(f(u)\) 的瓶颈,于是可以通过操作增大 \(a_u\),减小 \(g(u)\) 做到平衡。

所以可以让 \(a_u\) 和 \(g_u\) 都变成 \(\dfrac{g(u)+a_u}{2}\) 即可。

注意下取整一下。

注意到如果 \(a_u>g(u)\),那么答案不会变大,\(f(u)=g(u)\),特判一下。

所以有

\(f(u)=\min\left(a_u,\dfrac{\min_{v\in sons(u)}f(v)+a_u}{2}\right)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 2e5 + 5;
ll n, f[N], a[N];
vector<int> e[N];

void dfs(int x)
{
    if(e[x].empty()) return f[x] = a[x], void();
    f[x] = 0;
    ll mn = 2e9;
    for(int i : e[x])
    {
        dfs(i);
        mn = min(mn, f[i]);
    }
    if(x == 1) cout << a[1] + mn << "\n";
    if(a[x] >= mn) f[x] = mn;
    else f[x] = (mn + a[x]) / 2;
}

void solve()
{
    cin >> n;
    for(int i = 1; i <= n; i ++) e[i].clear();
    for(int i = 1; i <= n; i ++) cin >> a[i];
    for(int i = 2; i <= n; i ++)
    {
        int x; cin >> x;
        e[x].push_back(i);
    }
    dfs(1);
}

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    int t;cin >> t;while(t --) solve();

    return 0;
}

E. Level Up

法一:考虑主席树

注意到 \(\sum_{i=1}^n \frac 1i=O(n\log n)\)。

所以离线下来,对于每个 \(k\) 枚举等级增加的位置,也就是 \(O(n\log n)\) 个。

于是问题变成:求最小的 \(r\) 使得 \(\sum_{i=l}^r[a_i\geq lev]=k\),这可以在 \(a_i\) 的大小这一维上可持久化一下,以 \(i\) 为下标,线段树上二分一下就可以了,复杂度 \(O(n\log^2n)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 2e5 + 5, V = 2e5;

int rt[N];
int fdp;
struct sgt
{
    int a[N << 6], ls[N << 6], rs[N << 6], idx;
    inline void pu(int x) {a[x] = a[ls[x]] + a[rs[x]];}
    int upd(int q, int l, int r, int x, int v)
    {
        int u = ++idx; a[u] = a[x], ls[u] = ls[x], rs[u] = rs[x];
        if(l == r) return a[u] += v, u;
        int mid = l + r >> 1;
        if(mid >= q) ls[u] = upd(q, l, mid, ls[x], v);
        else rs[u] = upd(q, mid + 1, r, rs[x], v);
        pu(u); return u;
    }
    void fnd(int l, int r, int x, int k)
    {
        if(l == r) return fdp = l, void();
        int mid = l + r >> 1;
        if(a[ls[x]] >= k) return fnd(l, mid, ls[x], k);
        else return fnd(mid + 1, r, rs[x], k - a[ls[x]]);
    }
    int qry(int ql, int qr, int l, int r, int x, int k)
    {
        if(ql > qr) return 0;
        if(ql <= l && r <= qr)
        {
            if(a[x] < k) return a[x];
            return fnd(l, r, x, k), k;
        }
        int mid = l + r >> 1, ans = 0;
        if(mid >= ql) ans += qry(ql, qr, l, mid, ls[x], k);
        if(ans < k && mid < qr) ans += qry(ql, qr, mid + 1, r, rs[x], k - ans);
        return ans;
    }
}t;

vector<pair<int, int>> q[N];
int n, ans[N], Q, a[N];
vector<int> v[N];

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> Q;
    for(int i = 1; i <= n; i ++) cin >> a[i], v[a[i]].push_back(i);
    for(int i = V; i >= 1; i --)
    {
        rt[i] = rt[i + 1];
        for(int j : v[i])
            rt[i] = t.upd(j, 1, n, rt[i], 1);
    }
    for(int i = 1; i <= Q; i ++)
    {
        int x, y; cin >> x >> y;
        q[y].push_back({x, i});
    }
    for(int i = 1; i <= n; i ++)
    {
        if(q[i].empty()) continue;
        vector<int> pos;
        int lst = 0;
        for(int j = 1; j <= n / i; j ++)
        {
            if(t.qry(lst + 1, n, 1, n, rt[j], i) < i) break;
            pos.push_back(fdp);
            lst = fdp;
        }
        for(auto [j, id] : q[i])
        {
            int lev = lower_bound(pos.begin(), pos.end(), j) - pos.begin() + 1;
            ans[id] = a[j] >= lev;
        }
    }
    for(int i = 1; i <= Q; i ++)
        cout << (ans[i] ? "YES" : "NO") << "\n";

    return 0;
}

法二:

咕咕咕。

F. Chips on a Line

注意到这很像斐波那契数列,又注意到 \(i\to i-1,i-2\),我们发现,一个位于 \(i\) 上的棋子等价于 \(fib_i\) 个位于 \(1\) 或 \(2\) 的棋子。(不断使用这个操作,反过来,可以使用逆操作)。

设 \(i\) 上有 \(c_i\) 个棋子,设状态 \(S=\sum_{i=1}^x c_i\times fib_i\)。

这个性质让我们发现,不同状态之间是不能转化的,相同状态之间是可以随便转化的,于是可以处理出每个 \(S\) 的代价。考虑 dp。

设 \(f(i)\) 为 \(S=i\) 时的代价。

于是有 \(f(i)=\min_{j=1}f(i-fib_j)+1\)。

然后考虑计数有多少个状态为 \(S\) 的方案,考虑背包,设 \(g(i,j,k)\) 表示 dp 到 \(fib_i\),填了 \(j\) 个棋子,状态为 \(k\) 的方案数,有:

\(g(i,j,k) = \sum_{c=0}g(i-1,j-c,k-c\times fib_i)\)。

复杂度不太对。

注意到这是一个完全背包,于是改写成:

\(g(i,j,k)=g(i,j-1,k-fib_i)+g(i-1,j,k)\)。

空间开不下。

滚动数组优化一下就好了。

答案就是 \(ans=\sum_{i=0} [f(i)=m]g(x,n,i)\)。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N = 1005, M = N * 60, p = 998244353;
int a[40];
int f[M], n, x, m;
int g[N][M];

signed main()
{
    ios::sync_with_stdio(0);cin.tie(0);
    cin >> n >> x >> m;

    a[1] = a[2] = 1;
    for(int i = 3; i < 40; i ++) a[i] = a[i - 1] + a[i - 2];

    memset(f, 0x3f, sizeof f);
    f[0] = 0;
    for(int i = 1; i < M; i ++)
        for(int j = 0; j < 40; j ++)
            if(i >= a[j]) f[i] = min(f[i], f[i - a[j]] + 1);
    g[0][0] = 1;
    for(int i = 1; i <= x; i ++)
    {
        for(int j = 1; j <= n; j ++)
        for(int k = a[i]; k <= n * 55; k ++)
            g[j][k] = (g[j][k] + g[j - 1][k - a[i]]) % p;
    }
    ll ans = 0;
    for(int i = 1; i < M; i ++)
        ans += (f[i] == m) * g[n][i];
    cout << ans % p;

    return 0;
}

标签:return,int,题解,CF1997,edu168,long,cin,ans,mid
From: https://www.cnblogs.com/adam01/p/18334349

相关文章

  • 【题解】2024牛客多校第5场
    E安https://ac.nowcoder.com/acm/contest/81600/E分析简单博弈/思维题。当ai>bi时,当前骑士一定存活。当ai<bi时,当前骑士一定死亡。为了使得自己存活的骑士尽可能多,若存在ai=bi的情况,一定会选择令该骑士去攻击对方,并且双方均会轮流优先选择此类骑士。......
  • 07-30 题解
    07-30题解A朴素的想法$dp(i,j,k)$表示考虑到第\(i\)位,前\(i\)位的和为\(j\),第\(i\)位的值为\(k\)然后咋转移?重新定义移动小球的方式:从自己右边的邻居拿过来正数个球拿过来负数个球(即往右边的邻居放正数个球)在第2种操作中,我们拿走的球会被后面放过来......
  • Luogu P1983 车站分级 题解 [ 绿 ] [ 拓扑排序 ] [ 图论建模 ] [ 虚点 ]
    车站分级:很好的拓扑排序题,细节有点多。图论建模首先观察对于一条线路,我们可以从中直接得到什么信息:假设这条线路的开头为\(st\),结尾为\(ed\),那么在\([st,ed]\)的车站中,没有被选入线路的点一定比选入线路的点的级数至少少\(1\)。对于这一点条件,我们就可以建模了。......
  • CF538H Summer Dichotomy 题解
    Description有\(T\)名学生,你要从中选出至少\(t\)人,并将选出的人分成两组,可以有某一组是空的。有\(n\)名老师,每名老师要被分配到两个小组之一,对于第\(i\)名老师,要求所在的小组中的学生人数\(\in[l_i,r_i]\)。此外,有\(m\)对老师不能在同一个小组中。你需要判断能否......
  • SP8099 TABLE - Crash´s number table 题解
    题目传送门前置知识一般的积性函数|数论分块|莫比乌斯反演解法令\(n\lem\)。考虑莫比乌斯反演,推式子,有\(\begin{aligned}&\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\operatorname{lcm}(i,j)\\&=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\frac{ij}{\gcd(i,j)......
  • 题解:Pinely Round 4 (Div. 1 + Div. 2) A
    A.MaximizetheLastElementtimelimitpertest:1secondmemorylimitpertest:256megabytesinput:standardinputoutput:standardoutputYouaregivenanarray\(a\)of\(n\)integers,where\(n\)isodd.Inoneoperation,youwillremovetwoa......
  • P4449 于神之怒加强版 (题解)
    题目链接P4449于神之怒加强版题目大意:求\[\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)^k\]\(数据范围n,m\leq5e6\)\(二话不说,先开导式子(假定n<m):\)\begin{aligned}ans&=\sum_{i=1}^{n}\sum_{j=1}^{m}gcd(i,j)^k\\\end{aligned}\[先套路地枚举d=gcd(i,j)\]\begin{align......
  • 题解 - Alice
    题目描述Alice和Bob在玩游戏,游戏规则如下:有两堆石子,每堆石子有非负整数个Alice与Bob轮流操作,Alice先手,每次可以从任意一堆石子中取出若干个取出的石子个数应满足为另一堆石子个数的因数(此处规定任何数均为0的因数)将石子取完的玩家获胜给定一个初始状态,现......
  • [POI2007] OSI-Axes of Symmetry 题解
    给出一个多边形,求对称轴数量。考虑对于一个多边形,其是对称的当且仅当对于若干个边(角),其左右的角与边都是对称的。考虑如果我们对于内角构造出一种单射,映射为一个整数,将边映射为它的边长,那么我们按照角,边,角,边,……的顺序将他们加入数组中,能构造出一个长度为\(2n\)的数组,将这个......
  • 旅行 题解
    题目id:20300题目描述鱼大大计划环华夏自驾游游玩一圈,在他的计划中,这次旅行将在\(m\)天内完成,预计游玩\(n\)个城市,每个城市游玩\(x\)天,然后赶路开车以均速去到下一个城市,现鱼大大从海洋城市出发,按游玩顺序先后给出每个城市和上一个城市之间的距离(\(km\)),问鱼大大每天至少赶路多......