2022上海市赛SHCPC【个人题解AEGHILMN】

算法竞赛技巧
本文介绍了算法竞赛中的多种解题策略,包括暴力枚举、动态规划、AC自动机等,并提供了具体的题目示例及代码实现。

A - Another A+B Problem(暴力)

思路

暴力枚举第一个数字和第二个数字(99*99),判断是否满足GPB的条件即可。
判断是否满足条件的话就乱搞一下就可以了,具体看代码。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

typedef pair<int, int> PII;

char a[10], b[10];

bool B[10];
int P[10];
int G[10];

bool vis[10];
int cnt[10];

bool check(int i, int j, int k)
{
   
   
    vector<int> c(10);
    c[0] = i / 10, c[1] = i % 10;
    c[3] = j / 10, c[4] = j % 10;
    c[6] = k / 10, c[7] = k % 10;

    for (int i = 0; i < 10; i ++ )
        cnt[i] = 0;
    for (int j = 0; j <= 7; j ++ )
        if (j != 2 && j != 5)
            cnt[c[j]] ++;

    for (int j = 0; j <= 7; j ++ )
    {
   
   
        if (j == 2 || j == 5) continue;
        if (b[j] == 'G')
        {
   
   
            if (c[j] != a[j] - '0') return false;
        }
        else 
        {
   
   
            if (c[j] == a[j] - '0') return false;
            if (b[j] == 'B')
            {
   
   
                if (cnt[a[j] - '0'] != G[a[j] - '0'] + P[a[j] - '0']) 
                    return false;
            }
        }
    }

    for (int i = 0; i < 10; i ++ )
        if (cnt[i] - G[i] < P[i]) return false;
    
    return true;
            
}

int main()
{
   
   
    #ifdef ZYCMH
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
    #endif

    scanf("%s", a);
    scanf("%s", b);

    for (int i = 0; b[i]; i ++ )
        if (b[i] == 'B')
            B[a[i] - '0'] = true;
        else if(b[i] == 'P')
            P[a[i] - '0'] ++;
        else if (b[i] == 'G' && a[i] != '+' && a[i] != '=') 
            G[a[i] - '0'] ++;
    
    vector<PII> ans;
    for (int i = 0; i <= 99; i ++ )
        for (int j = 0; j <= 99; j ++ )
            if (i + j <= 99 && check(i, j, i + j))
                ans.push_back(make_pair(i, j));

    int sz = ans.size();
    printf("%d\n", sz);
    for (int i = 0; i < sz; i ++ )
        printf("%d%d+%d%d=%d%d\n", ans[i].first / 10, ans[i].first % 10, ans[i].second / 10, ans[i].second % 10, (ans[i].first + ans[i].second) / 10, (ans[i].first + ans[i].second) % 10);
    return 0;
}

E - Expenditure Reduction(dp)

思路

f [ i ] [ j ] f[i][j] f[i][j]表示包含 F [ 1.. i ] F[1..i] F[1..i]的以 S [ j ] S[j] S[j]结尾的子串中,最短的子串的开始位置,那么显然有以下转移方程:
f [ i ] [ j ] = m a x ( f [ i − 1 ] [ k ] ) , ( S [ k ] = = F [ i − 1 ] , k < = j − 1 ) f[i][j] = max(f[i - 1][k]), (S[k] == F[i - 1], k <= j - 1) f[i][j]=max(f[i1][k]),(S[k]==F[i1],k<=j1)
由于要满足 S [ k ] = = F [ i − 1 ] S[k] == F[i - 1] S[k]==F[i1],于是只需要记下每个字符的 f [ i − 1 ] f[i - 1] f[i1]的最大前缀状态(这个前缀是针对于S串中的位置)即可实现 O ( 1 ) O(1) O(1)转移,详细见代码。

代码

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 100005, INF = 0x3f3f3f3f;

int n, m
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值