Codeforces Round #748 (Div. 3) 题解代码

题目链接

A

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
const int N = 1e4 + 10;


int main()
{
    int T;
    cin >> T;
    while(T--)
    {
        int mx = 0;
        int a[3];
        cin >> a[0] >> a[1] >> a[2];
        mx = max(max(a[0], a[1]), a[2]);
        int cnt = 0;
        for(int i = 0; i < 3; i++) if(a[i] == mx) cnt++;
        for(int i = 0; i < 3; i++)
        {
            printf("%d ", a[i] == mx && cnt == 1 ? 0 : mx + 1 - a[i]);
        }
        puts("");
    }
    
    return 0;
}

B

这题需要枚举后面的两位,看看是否可以%25==0整除,然后前面的数组随意。所以最后两位有25,50,00,75四种情况

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#define x first
#define y second
typedef pair<int,int> PII;
typedef long long LL;
const int N = 1e4 + 10, INF = 0x3f3f3f3f;
LL k, n;
int nums[29], cnt, mx;

//len已经选择的数字
int get(int arr[])
{
    int res = 0;
    int i = cnt - 1, j = 1;
    while(i >= 0 && j >= 0)
    {
        // printf("arr[j]=%d ", arr[j]);
        while(i >= 0 && nums[i] != arr[j]) i--, res++; 
        // printf("del=%d ", nums[i + 1]);
        // puts(""); 
        if(i >= 0 && nums[i] == arr[j])
        {
            i--, j--;
            // printf("i=%d,j=%d\n", i, j);
        }
    }
    if(j >= 0) return res = INF;
    // printf("n=%lld, %d%d, %d\n", k, arr[0],arr[1], res);
    return res;
}

int main()
{
// #ifdef ONLINE_JUDGE
// #else 
//     freopen("in.txt", "r", stdin);
// #endif
    int T;
    cin >> T;
    while(T--)
    {
        cin >> n;
        k = n;
        cnt = 0;
        while(n) nums[cnt++] = n % 10, n /= 10;
        reverse(nums, nums + cnt);
        // for(int i = 0; i < cnt; i++) printf("%d ", nums[i]);
        // puts("");
        int res = INF;
        int arr[2] = {0, 0};
        res = min(res, get(arr));
        arr[0] = 2, arr[1] = 5;
        res = min(res, get(arr));
        arr[0] = 5, arr[1] = 0;
        res = min(res, get(arr));
        arr[0] = 7, arr[1] = 5;
        res = min(res, get(arr));
        printf("%d\n", res);
    }
    
    return 0;
}

C

二分即可

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 4e5 + 10;
typedef long long LL;

int n, k;
int a[N];

bool check(int mid)
{
    LL sum = 0;
    for(int i = mid; i < k; i++)
    {
        if(sum >= a[i]) return false;
        sum += n - a[i];
    }
    return true;
}
int main()
{
// #ifdef ONLINE_JUDGE
// #else 
//     freopen("D.txt", "r", stdin);
// #endif
    
    int T;
    cin >> T;
    while (T--)
    {
       cin >> n >> k;
       for(int i = 0; i < k; i++) cin >> a[i];
       sort(a, a + k);
       int l = 0, r = k - 1;
       while(l < r)
       {
           int mid = l + r >> 1;
           if(check(mid)) r = mid;
           else l = mid + 1;
       }
       cout << k - l << endl;
    }
    
    
    return 0;
}

D1

如果不是全部相等,则求一个最大公约数就可以了

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
typedef long long LL;
const int N = 4e5 + 10, M = N + N;
int n;
int a[N];
int gcd(int a, int b)
{
    return !b ? a : gcd(b, a % b);
}
int main()
{
// #ifdef ONLINE_JUDGE
// #else 
//     freopen("G.txt", "r", stdin);
// #endif
    int T;
    cin >> T;
    
    while(T--)
    {
        scanf("%d", &n);
        for(int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        sort(a, a + n);
        n = unique(a, a + n) - a;

        if(n == 1) puts("-1");
        else {
            int mx = a[1] - a[0];
            for(int i = 2; i < n; i++)
                mx = gcd(mx, a[i] - a[i - 1]);
            cout << mx << endl;
        }
    }
    
    return 0;
}

D2

如果都能变到某一个数,则必定某个差值的约数d1出现的次数>=n/2

#include <iostream>
#include <cstring>
#include <map>
#include <unordered_map>
using namespace std;
const int N = 100;
typedef pair<int,int> PII;

int n;
int a[N];
PII p[N];

map<int,int> S;
unordered_map<int,int> cnt;
void get(int x, int k)
{
    for(int i = 1; i * i <= x; i++)
    {
        if(x % i == 0) 
        {
            cnt[i] += k;
            if(x / i != i) cnt[x / i] += k;
        }
    }
}
int main()
{
#ifdef ONLINE_JUDGE
#else 
    freopen("D.txt", "r", stdin);
#endif
    
    int T;
    cin >> T;
    while (T--)
    {
        S.clear();
        
        cin >> n;
        int mx = 0;
        for(int i = 0; i < n; i++) cin >> a[i], mx = max(mx, ++S[a[i]]);
        if(mx >= n / 2) {
            puts("-1");
            continue;
        } 

        int len = 0;
        for(auto&[k, v]: S) p[len++] = {k, v};

        int ans = 0;
        for(int i = 0; i < len; i++)
        {
            cnt.clear();
            for(int j = i + 1; j < len; j++)
            {
                get(p[j].first - p[i].first, p[j].second);
            }

            for(auto&[k, v]: cnt)
            {
                if(v + p[i].second >= n / 2)
                    ans = max(ans, k);
            }
        }
        cout << ans << endl;   
    }
    
    
    return 0;
}

E

从度数为1的点开始bfs,简单模拟一下就可以

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
typedef pair<int, int> PII;
#define x first
#define y second
typedef long long LL;
const int N = 4e5 + 10, M = N + N;
int n, k;
int h[N], e[M], ne[M], idx;
int d[N], q[N], p[N];
bool st[N];

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}

int main()
{
// #ifdef ONLINE_JUDGE
// #else 
//     freopen("G.txt", "r", stdin);
// #endif
    int T;
    cin >> T;
    while (T--)
    {
        cin >> n >> k;
        idx = 0;
        if(n == 1) {
            puts("0");
            continue;
        }
        memset(h, -1, (n + 1) * 4);
        memset(d, 0, (n + 1) * 4);
        for(int i = 0; i < n - 1; i ++)
        {
            int a, b;
            cin >> a >> b;
            add(a, b), add(b, a);
            d[b]++, d[a]++;
        }

        int hh = 0, tt = -1;
        int tot = 0;
        for(int i = 1; i <= n; i++) if(d[i] == 1) q[++tt] = i;

        while(k && tot < n) {  
            
            int cnt = 0;
            while(hh <= tt)
            {
                //删除当前点
                int t = q[hh++];
                tot++;
                for(int i = h[t]; ~i; i = ne[i])
                {
                    int j = e[i];
                    if(--d[j] == 1) p[cnt++] = j;
                }
            }
            hh = 0, tt = -1;
            for(int i = 0; i < cnt; i++) q[++tt] = p[i];
            k--;
        }
        printf("%d\n", n - tot);
    }
    
    return 0;
}

F

f[i][j][a][b]表示,考虑了前i位,选了j位红色的数字,且红色数字modA=a,mod B = b的方案集合
属性:是否可以到达这个状态,true表示可以,false表示不行
状态转移
第i+1位红色:f[i][j][a][b] -> f[i + 1][j + 1][(a * 10 + x) % A][b]
黑色: f[i][j][a][b] -> f[i + 1][j][a][(b * 10 + x) % b]
刚开始的状态是f[0][0][0][0] = true
要输出方案,所以记录每个状态由哪几个状态转移而来, 由状态转移可以发现,后一个状态只需要记录前一个的余数,以及前一个被染成啥颜色即可

这里提供两种不同的写法,一种是倒推,一种是开一个数组记录上一个状态

记录上一个状态

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
const int N = 45;


bool f[N][N][N][N];
pair<bool, int> pre[N][N][N][N];
int n, A, B;
char s[N];
int main()
{
#ifdef ONLINE_JUDGE
#else 
    freopen("in.txt", "r", stdin);
#endif

    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> A >> B >> s;

        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= n; j++)
                for(int a = 0; a < A; a++)
                    for(int b = 0; b < B; b++) 
                        f[i][j][a][b] = false;
        
        f[0][0][0][0] = true;
        for(int i = 0; i < n; i++)
            for(int j = 0; j <= i; j++)
                for(int a = 0; a < A; a++)
                    for(int b = 0; b < B; b++)
                        if(f[i][j][a][b])
                        {
                            int x = s[i] - '0';
                            f[i + 1][j + 1][(a * 10 + x) % A][b] = true;
                            pre[i + 1][j + 1][(a * 10 + x) % A][b] = {true, a};

                            f[i + 1][j][a][(b * 10 + x) % B] = true;
                            pre[i + 1][j][a][(b * 10 + x) % B] = {false, b};
                        }
        int red_cnt = 50, d = 50;
        for(int i = 1; i < n; i++)
        {
            int b = n - i;
            if(f[n][i][0][0] && abs(i - b) < d) red_cnt = i, d = abs(i - b);
        }

        if(red_cnt == 50) puts("-1");
        else 
        {
            string ans = "";
            int x = 0, y = 0;
            for(int i = n; i; i--)
            {
                auto t = pre[i][red_cnt][x][y];
                if(t.first) 
                {
                    ans.push_back('R');
                    red_cnt--;
                    x = t.second;
                }
                else {
                    ans.push_back('B');
                    y = t.second;
                }
            }
            
            reverse(ans.begin(), ans.end());
            cout << ans << endl;
        }
    }
    return 0;
}

倒推

#include<iostream>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;
const int N = 45;
bool f[N][N][N][N];
int n, A, B;
char s[N];
string ans;

void get_pre(int n, int& cnt, int& x, int& y)
{
    for(int j = 0; j <= cnt; j++)
        for(int a = 0; a < A; a++)
            for(int b = 0; b < B; b++)
            {
                int v = s[n] - '0';
                if((a * 10 + v) % A == x && b == y && j + 1 == cnt && f[n][j][a][b] == f[n + 1][cnt][x][y])
                {
                    ans.push_back('R');
                    cnt--;
                    x = a;
                    return;
                }
                else if((b * 10 + v) % B == y && a == x && j == cnt && f[n][j][a][b] == f[n + 1][cnt][x][y])
                {
                    ans.push_back('B');
                    y = b;
                    return;
                }
            }
}
int main()
{
#ifdef ONLINE_JUDGE
#else 
    freopen("in.txt", "r", stdin);
#endif

    int T;
    cin >> T;
    while(T--)
    {
        cin >> n >> A >> B >> s;

        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= n; j++)
                for(int a = 0; a < A; a++)
                    for(int b = 0; b < B; b++) 
                        f[i][j][a][b] = false;
        
        f[0][0][0][0] = true;
        for(int i = 0; i < n; i++)
            for(int j = 0; j <= i; j++)
                for(int a = 0; a < A; a++)
                    for(int b = 0; b < B; b++)
                        if(f[i][j][a][b])
                        {
                            int x = s[i] - '0';
                            f[i + 1][j + 1][(a * 10 + x) % A][b] = true;
                       

                            f[i + 1][j][a][(b * 10 + x) % B] = true;
                          
                        }
        int red_cnt = 50, d = 50;
        for(int i = 1; i < n; i++)
        {
            int b = n - i;
            if(f[n][i][0][0] && abs(i - b) < d) red_cnt = i, d = abs(i - b);
        }

        if(red_cnt == 50) puts("-1");
        else 
        {
            ans = "";
            int x = 0, y = 0;
            for(int i = n - 1; ~i; i--)
                get_pre(i, red_cnt, x, y);
            
            reverse(ans.begin(), ans.end());
            cout << ans << endl;
        }
    }
    return 0;
}

G. Changing Brackets

观察发现,如果一个[l, r]中全部是圆括号,那么答案则一定是0(可以把左边的一半全部变成 ( ( (,右边的一半全部变成 ) ) )

那么可以考虑这样一个问题,答案应该只和方括号的数量有关。记方括号下表为奇数的个数为 c n t o d d cnt_{odd} cntodd,下标为偶数的个数为 c n t e v e n cnt_{even} cnteven,那么,只要 c n t e v e n = c n t o d d cnt_{even}=cnt_{odd} cnteven=cntodd,答案就是0

可以证明,对于一个合法的匹配,必定等价于 c n t e v e n = c n t o d d cnt_{even}=cnt_{odd} cnteven=cntodd

必要性:可以观察得到,合法的括号匹配,一定是一个奇数位置和偶数位置的括号进行匹配,匹配后,就可以得到 c n t e v e n − 1 cnt_{even}-1 cnteven1 c n t o d d − 1 cnt_{odd}-1 cntodd1个方括号,若 c n t e v e n ! = c n t o d d cnt_{even} != cnt_{odd} cnteven!=cntodd,那么比定有某些方括号被剩下来了,这和原来是个合法匹配矛盾。

充分性:找到最近的两个奇数位置和偶数位置的括号,他们中间一定是有偶数个画括号,那么这些括号会形成一个合法匹配。可以先把这些括号从序列中去掉(去掉合法序列后不影响正确性),会得到 c n t e v e n − 1 cnt_{even}-1 cnteven1 c n t o d d − 1 cnt_{odd}-1 cntodd1个方括号。再重复上面的过程,直到 c n t e v e n = 0 cnt_{even}=0 cnteven=0 c n t o d d − 1 = 0 cnt_{odd-1}=0 cntodd1=0。那么这样剩下的就全部是圆括号了,所以答案就是0

#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e6 + 10;
typedef long long LL;
char str[N];
int n, m;
int s[N][2];
int main()
{
#ifdef ONLINE_JUDGE
#else 
    freopen("C.txt", "r", stdin);
#endif
    int T;
    cin >> T;
    while(T--) {
        scanf("%s", str + 1);
        n = strlen(str + 1);
        for(int i = 1; i <= n; i++) {
            s[i][0] = s[i - 1][0], s[i][1] = s[i - 1][1];
            if(str[i] == '[' || str[i] == ']') s[i][i & 1] += 1;
        }

        scanf("%d", &m);
        while (m--)
        {
            int l, r;
            scanf("%d%d", &l, &r);
            int odd = s[r][1] - s[l - 1][1];
            int even = s[r][0] - s[l - 1][0];
            printf("%d\n", abs(odd - even));
        }
        
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值