2025CCPC陕西省赛

  • define时间:
#define itn int
#define int long long
#define ind long double
#define yes cout << "Yes"
#define no cout << "No"
#define pii pair<long long, long long>
#define pci pair<char, int>
#define re return;

L.easy

签到,手玩样例容易发现按照题目要求随便取数即可。

简单地考虑,第一行为 1+2=31+2=31+2=3,除去最后一行的每行在这基础上加上 (n+1)∗2(n+1)*2(n+1)2,最后一行加上首尾两个数即可。

void solve(){
    int ans = 3;
    int t = 3;
    for (int i = 2; i < n; i++)
    {

        t += (n + 1) * 2;
        ans += t;
    }
    ans += n * n + (n * n - n + 1);
}

某位cf1700分选手一激动在这题卡了12分钟,警示大家卡题不要激动,冷静找出bug。

G.学生

思维题,首先容易发现最左端和最右端一定无法删除。

其次,如果最大值和最小值在中间也无法删除。

所以 ansansans 即为 2+2+2+ 不在左右端的最大最小值个数。

void solve(){    
    maxn = *max_element(a + 1, a + 1 + n);
    minn = *min_element(a + 1, a + 1 + n);
    if (a[1] != maxn && a[n] != maxn)
    {
        ans++;
    }
    if (a[1] != minn && a[n] != minn)
    {
        ans++;
    }
    cout << ans;
}

注意 n 的范围,最小为 1 。所以需要特判

if (n == 1)
    {
        cout << 1;
        re;
    }

C.最大公因数

题意:问是否存在一个数和 bbb 不互质,和 aaa 互质。

我们从 bbb 往下找,记作 b1b1b1,每次除以 gcd(a,b)gcd(a,b)gcd(a,b),直到 gcd(a,b)=1gcd(a,b)=1gcd(a,b)=1,意味着此时的 b1b1b1aaa 互质。

如果此时 gcd(b1,b)!=1gcd(b1,b)!=1gcd(b1,b)!=1,则有解;反之无解。

void solve(){  
        int a, b;
        cin >> a >> b;
        int b1 = b;
        while (gcd(b1, a) != 1)
        {
            b1 /= gcd(b1, a);
        }
        cout << (gcd(b1, b) != 1 ? b1 : -1) << '\n';
}

J.赢

题意:问最多加 kkk 个字符,能组成多少个 lose。

可以发现添加字符能组成 lose 的字符串是有限的,不妨用 mapmapmap 存储记录一下各种串的个数,放进堆里,枚举即可得到答案。

需要注意:多余的 kkk 可以通过每次取 444 组成 lose。

void solve()
{
    map<string, int> mp;//map存储各种串组成lose需要的k的个数
    mp["lose"] = 0;
    mp["los"] = mp["loe"] = mp["ose"] = mp["lse"] = 1;
    mp["lo"] = mp["ls"] = mp["le"] = mp["os"] = mp["oe"] = mp["se"] = 2;
    mp["l"] = mp["o"] = mp["s"] = mp["e"] = 3;
    cin >> k >> s1;
    n = s1.size();
    priority_queue<int, vector<int>, greater<int>> pq;//vp时堆开反wa了一发
    string ss = "";
    ans = 0;
    for (int i = 0; i < n; i++)
    {
        string tp = ss + s1[i];
        if (mp.find(tp) != mp.end())
        {
            ss = tp;
        }
        else
        {
            if (mp.find(ss) != mp.end())
                pq.push(mp[ss]);
            ss = "";
            ss += s1[i];
        }
    }
    if (mp.find(ss) != mp.end())
        pq.push(mp[ss]);
 
    while (pq.size())
    {
        if (k >= pq.top())
        {
            ans++;
            k -= pq.top();
            pq.pop();
        }
        else
        {
            break;
        }
    }
    ans += k / 4;
    cout << ans;
}

D. 买股票

题意:给一个初始值和n个 +++∗* 的操作,求结果最大值。

贪心地考虑,先 +++∗* 一个较大的数,对后续的增长更有利。

观察到 n<=30n<=30n<=30,所以想到先将两种操作分开,按从大到小排序,然后 dfs 搜索找最大值即可。

#define ind double
void solve()
{
    ind v;
    cin >> n >> v;
    m = n;
    vector<ind> plus, mul;
    ind x;
    while (m--)
    {
        cin >> ch1 >> x;
        if (ch1 == '+')
        {
            plus.emplace_back(x);
        }
        else
        {
            mul.emplace_back(x);
        }
    }
    sort(plus.begin(), plus.end(), greater<>());
    sort(mul.begin(), mul.end(), greater<>());
    ind ans = 0;
    int L = plus.size(), R = mul.size();
    auto dfs = [&](auto &&dfs, int l, int r, ind cur, ind sum)
    {
        if (l == L && r == R)
        {
            ans = max(ans, sum);
            re;
        }
        if (l < L)
        {
            dfs(dfs, l + 1, r, cur + plus[l], sum + cur + plus[l]);
        }
        if (r < R)
        {
            dfs(dfs, l, r + 1, cur * mul[r], sum + cur * mul[r]);
        }
    };
    dfs(dfs, 0, 0, v, 0);
    cout << fixed << setprecision(10) << ans / n << "\n";
}

某人此题开了 long double卡了半小时,这警示我们少开long double和long long

K.库存

究极分讨题。

不妨依次讨论:

  1. 如果 m、nm、nmn 都为 000 ,则 ans=0ans=0ans=0

  2. 如果 nnn000x>yx>yx>y,自私都选 A ,那么 ans=xans=xans=x ;反之都选 B ,ans=m∗yans=m*yans=my

  3. 如果 mmm000x>yx>yx>y,无私一只选 A,其余选 B,那么 ans=x+(n−1)∗yans=x+(n-1)*yans=x+(n1)y ;否则全选 B,ans=n∗yans=n*yans=ny

  4. 如果 m、nm、nmn 都不为 000

    • x=0x=0x=0ans=(m+n)∗yans=(m+n)*yans=(m+n)y

    • y=0y=0y=0ans=xans=xans=x

      x、yx、yxy 都不为 000

    • 如果无私奶牛都选 B:x>yx>yx>yans1=x+n∗yans1=x+n*yans1=x+ny;反之,ans1=(n+m)∗yans1=(n+m)*yans1=(n+m)y

    • 如果无私有 ttt 只选 A,ans2=x+(n+m−t)∗yans2=x + (n + m - t) * yans2=x+(n+mt)y

      ans=min(ans1,ans2)ans=min(ans1,ans2)ans=min(ans1,ans2)

void solve()
{
    cin >> n >> m >> x >> y;
    if (n == 0 && m == 0)
    {
        cout << 0;
        re;
    }
    if (n == 0)
    {
        if (x > y)
        {
            cout << x;
            re;
        }
        else
        {
            cout << m * y;
            re;
        }
    }
    if (m == 0)
    {
        if (x > y)
        {
            cout << x + ((n - 1) * y);
            re;
        }
        else
        {
            cout << n * y;
            re;
        }
    }
    int cnt1 = 0, cnt2 = 0;
    if (m != 0 && n != 0)
    {
        if (x == 0)
        {
            cout << (m + n) * y;
            re;
        }
        else
        {
            if (y == 0)
            {
                cout << x;
                re;
            }
            else
            { // x,y都不为0
                // 1、如果无私都选y
                if (x > y)
                {
                    cnt1 = x + n * y;
                }
                else
                {
                    cnt1 = (n + m) * y;
                }
                // 2、如无私有t只选x,其余选y
                t = (x - 1) / y;
                if (t > 0 && t <= n)
                {
                    cnt2 = x + (n + m - t) * y;
                }
                cout << max(cnt1, cnt2);
                re;
            }
        }
    }
}

A.染色

考虑贪心。

假设一开始所有颜色都通过涂满,即 ans[i]=w[i]+nans[i]=w[i]+nans[i]=w[i]+n,然后贪心地求能减少的值。

首先首尾的连续段不用涂色,记录断开连续的首尾位。

如果中间的连续段 cnt>w[c[i]]cnt>w[c[i]]cnt>w[c[i]],说明我们不需要涂满,可以从前涂到连续段的起始,从连续段的末尾涂到后。

即用 ans[c[i]]ans[c[i]]ans[c[i]]减去这段。

void solve(){
    cin >> n;
    vector<int> c(n + 2);
    for (int i = 1; i <= n; i++)
    {
        cin >> c[i];
    }
    vector<int> w(n + 2);
    vector<int> ans((int)2e5 + 50);
    for (int i = 1; i <= n; i++)
    {
        cin >> w[i];
        ans[i] = w[i] + n;
    }
    int i = 1;
    int x = n, y = 1;
    while (i <= n)
    {
        if (c[i] == c[1])
        {

            ans[c[i]]--;
            i++;
        }
        else
        {
            x = i;
            break;
        }
    }
    i = n;
    while (i >= x)
    {
        if (c[i] == c[n])
        {

            ans[c[i]]--;
            i--;
        }
        else
        {
            y = i;
            break;
        }
    }
    if (x > y)
    {
        ans[c[1]] = 0;
    }
    int cnt = 1;
    for (int j = x; j <= y; j++)
    {
        if (c[j] == c[j - 1])
        {
            cnt++;
        }
        else
        {
            cnt = 1;
        }
        if (cnt > w[c[j]])
        {
            ans[c[j]]--;
        }
    }
    for (int i = 1; i <= n; i++)
    {
        cout << ans[i] << ' ';
    }
}

E.打字

状压dp。

f[i][j]f[i][j]f[i][j]:i 状态下,此时光标位于 j 位置。

  1. jjj 往前考虑,如果左移 kkk 的位置已经被打印,则让 cnt++cnt++cnt++ ;否则更新
  2. jjj 向后考虑,同理。
int a[30][30];
int f[1ll << 21][30];
void solve()
{
    cin >> n >> m >> t;
    cin >> s1;
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < m; j++)
        {
            cin >> a[i][j];
        }
    }
    for (int i = 0; i < (1 << 21); ++i)
    {
        fill(f[i], f[i] + 30, inf);
    }
    for (int j = 0; j < n; j++)
        f[1 << j][j] = a[0][(int)(s1[j] - 'a')];
    for (int i = 0; i < (1ll << n); i++)  //遍历状态
    {
        for (int j = 0; j < n; j++)  //遍历位置
        {
            cnt = 1; //往前考虑,因为光标在最后,默认cnt为 1
            for (int k = j - 1; k >= 0; k--)
            {
                int tp = i | (1ll << k);
                if (i & (1ll << k)) //该位置已经被打印,继续左移,cnt+1
                {
                    cnt++;
                }
                else
                {
                    f[tp][k] = min(f[tp][k],
                                   f[i][j] + t * cnt + a[(int)(s1[j] - 'a')][(int)(s1[k] - 'a')]);
                }
            }
            cnt = 0;//往后考虑
            for (int k = j + 1; k < n; k++)
            {
                int tp = i | (1ll << k);
                if (i & (1ll << k))
                {
                    cnt++;
                }
                else
                {
                    f[tp][k] = min(f[tp][k],
                                   f[i][j] + t * cnt + a[(int)(s1[j] - 'a')][(int)(s1[k] - 'a')]);
                }
            }
        }
    }
    cout << n * t + *min_element(f[(1ll << n) - 1], f[(1ll << n) - 1] + n);
}
<think>好的,我需要帮助用户找到2024年CCPC辽宁省的题目解析或解决方案。首先,我需要确认目前是否有公开的题解资料。由于现在的时间是2023年10月,而用户询问的是2024年的比,显然该事还未举行,因此相关的题解自然不存在。这种情况下,我需要向用户说明这一点,避免他们继续无效搜索。 接下来,我应该考虑用户可能的实际需求。也许他们误写了年份,或者希望提前准备未来的比。如果是后者,我可以提供往届CCPC辽宁区的题解链接和资源,帮助他们进行备战。同时,还可以给出一般性的ACM竞解题策略和训练建议,这对用户来说可能同样有用。 此外,用户可能对比的具体题型和难度感兴趣。因此,我应当总结常见的考点,比如动态规划、图论、数据结构等,并推荐相应的学习资料和练习题。同时,提醒用户关注官方网站和社区,以获取最新的比信息。 最后,我需要确保回答结构清晰,分点说明,并且语言友好,让用户感受到帮助和支持。可能还需要生成相关问题,引导用户进一步提问,例如如何备、往届题解获取方式等,这样可以更全面地满足他们的需求。</think>### 2024年CCPC辽宁省题解信息 由于2024年CCPC辽宁省尚未举办(截至2023年10月),目前没有官方题解或完整解析公开。但可以通过以下途径获取备支持: --- ### 一、往届题解参考 1. **2023年CCPC辽宁区题目分析** 部分题目思路已在算法社区讨论,例如: - 动态规划问题中状态转移方程的优化技巧[^1] - 图论题常用**Dijkstra算法**的变体实现(使用优先队列优化) $$ \text{时间复杂度: } O((E+V)\log V) $$ - 字符串匹配问题中**KMP算法**的应用案例 2. **资源平台** - [Codeforces题解归档](https://codeforces.com/)(搜索"CCPC Liaoning"关键词) - [知乎专栏《ACM竞实战笔记》](https://zhuanlan.zhihu.com/)(含区域题型解析) --- ### 二、通用解题策略 1. **高频考点** | 题型 | 典型方法 | |------------|--------------------------| | 动态规划 | 状态压缩、滚动数组优化 | | 数论 | 模运算性质、欧拉定理应用 | | 数据结构 | 线段树区间操作、并查集路径压缩 | 2. **代码模板建议** ```python # 快速幂模算法模板(应对数论题) def qpow(a, b, mod): res = 1 while b: if b % 2 == 1: res = res * a % mod a = a * a % mod b //= 2 return res ``` --- ### 三、最新信息获取 1. **官方渠道** - CCPC官网(http://ccpc.io/)定期更新程 - 辽宁省计算机学会通知公告栏 2. **社群动态** - QQ群搜索"2024CCPC辽宁备战群" - GitHub开源项目"ACM-ICPC-LaTeX-Template"[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值