HZNU Winter Trainning 7 补题 - Zeoy

CodeForces - 1660C
题目传送门:https://vjudge.net/contest/535955#problem/C
题意:询问一个字符串最少删去几个字符,能够把这个字符串变成aabbccdd这种两两相同的字符串
题解:我们来一个样例:aabbdabbdccc,就这个样例我们可以从前往后遍历,如果map发现一个字符出现了两次,那就说明这个字符我们不需要删去,我们只需要删去map中除了这个字符的所有字符即可,或者我们可以倒着想,我们用字符串长度ans减去2即可,最后的ans一定代表现在需要删去的字符数量,我们能够去实践出这种删除方法一定是最贪的,就这个样例而言,ans=12,aa ans-=2;bb ans-=2;dabb ans-=2;dcc ans-=2;c;最终ans=4。

点击查看代码
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
map<char, int> mp;
int main(void)
{
    Zeoy;
    int t;
    cin >> t;
    while (t--)
    {
        mp.clear();
        string s;
        cin >> s;
        int n = s.length();
        s = "*" + s;
        int ans = n;
        for (int i = 1; i <= n; ++i)
        {
            if (mp[s[i]] == 0)
                mp[s[i]]++;
            else
            {
                ans -= 2;
                mp.clear();
            }
        }
        cout << ans << endl;
    }
    return 0;
}

CodeForces - 1660D
题目传送门:https://vjudge.net/contest/535955#problem/D
题意:给你一个数组a,里面的元素ai∈[-2,2],让你求数组首尾各删掉多少个元素,能够得到最大的数组各元素之积,并规定空数组值为1
题解:我们可以想一想对于一个数组中的0来说,我们去乘0没有意义,不管怎么都还是0,所以实际上0其实是分界线,我们把一个数组通过0分成几段,然后我们对每段进行处理,但是注意n的范围:1≤n≤2e5,说明如果我们把乘积乘出来一定会爆long long,所以我们决定把幂次记录,因为只有±1和±2的存在,对于每段数组大小我们用±2的数量记录,同时我们也要去记录元素<0的数量,所以一定会出现两种情况:
1.这一段积本身>0:也就是说小于0的元素的个数是偶数,那么这就是答案,我们不需要处理,再怎么处理,积的大小只会减小;
2.这一段积本身<0:也就是说小于0的元素的个数是奇数,那么我们需要找到从左边找的第一个负数和从右边找起的第一个负数,比较删去哪一个会使积更大
每一次求出来的积,我们还需要和ans比较,取大者,并记录左区间l和右区间r,最后输出即可。
`

点击查看代码
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int main(void)
{
    Zeoy;
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        vector<int> a(n + 2), pre1(n + 2), pre2(n + 2); 
        for (int i = 1; i <= n; ++i)
        {
            cin >> a[i];
            pre1[i] = pre1[i - 1] + (abs(a[i]) == 2);       //前缀和记录±2的个数
            pre2[i] = pre2[i - 1] + (a[i] < 0);             //前缀和记录负数的个数
        }
        a.push_back(0);                                     //保证最后一段能够被处理
        vector<int> v;
        int ans = -inf;                                     //代表区间中±2最多的个数,即幂次
        int l, r;
        for (int i = 1; i <= n + 1; ++i)
        {
            if (a[i] != 0)                                  //将各段分割在v中
                v.push_back(i);                             //一个细节:将下标存在v中
            else
            {
                int k = v.size();
                if (k == 0)
                    continue;
                int cnt = pre2[v[k - 1]] - pre2[v[0] - 1];  //求负数的个数
                // cout << cnt << endl;
                if (cnt % 2 == 0)                           //负数个数是偶数的情况,本身就是答案
                {
                    if (pre1[v[k - 1]] - pre1[v[0] - 1] > ans)
                    {
                        ans = pre1[v[k - 1]] - pre1[v[0] - 1];
                        l = v[0];
                        r = v[k - 1];
                    }
                }
                else                                        //负数个数是奇数的情况,我们找左边和右边第一个负数
                {
                    int ii = -1, jj = -1;
                    for (int i = 0; i < k; ++i)
                    {
                        if (a[v[i]] < 0)
                        {
                            ii = i;
                            break;
                        }
                    }
                    for (int i = k - 1; i >= 0; --i)
                    {
                        if (a[v[i]] < 0)
                        {
                            jj = i;
                            break;
                        }
                    }
                    if (pre1[v[k - 1]] - pre1[v[ii]] > ans)
                    {
                        ans = pre1[v[k - 1]] - pre1[v[ii]];
                        l = v[ii] + 1;
                        r = v[k - 1];
                    }
                    if (pre1[v[jj] - 1] - pre1[v[0] - 1] > ans)
                    {
                        ans = pre1[v[jj] - 1] - pre1[v[0] - 1];
                        l = v[0];
                        r = v[jj] - 1;
                    }
                }
                v.clear();                                    //别忘记清空容器
            }
        }
        if (ans < 1)                                          //别忘记空数组=1,如果没有±2,我们直接将数组删完
        {
            cout << "0 " << n << endl;
        }
        else
        {
            cout << l - 1 << " " << n - r << endl;
        }
    }
    return 0;
}
`

CodeForces - 1660E
题目传送门:https://vjudge.net/contest/535955#problem/E
题意:给你一个只有0和1的矩阵,你可以进行两种操作,一种是将矩阵上下左右滚动,类似环,这种操作没有花费;另一种是可以将任意元素反转,
1->0,0->1,这种操作每一花费为1,让你用最小花费将矩阵变为单位阵。
题解:我们很容易能求出将矩阵变为单位阵的花费:矩阵所有元素个数-对角线上1的个数-非对角线上0的个数=nn-n-num0-2y,y代表对角线上1的个数,我们发现想要使得花费最小,因为n和num0是一定的,所以我们只要使得对角线上的1最多即可,那么对于这一个可以滚动的类似环的操作我们该怎么去求

或者我们再拼三个一样的矩阵

本质没有区别

点击查看代码
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
char g[2010][2010] = {0};
int main(void)
{
    Zeoy;
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        ll cnt0 = 0;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                cin >> g[i][j];
                if (g[i][j] == '0')
                    cnt0++;
            }
        }
        int ans = 0;
        for (int k = 1; k <= n; ++k)
        {
            int sum = 0;
            int j = k;
            for (int i = 1; i <= n; ++i)
            {
                sum += g[i][j] - '0';
                j = j % n + 1;
            }
            ans = max(sum, ans);
        }
        cout << n * n - ans - (cnt0 - (n - ans)) << endl;
    }
    return 0;
}
点击查看代码
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
char g[4025][4025] = {0};
int main(void)
{
    Zeoy;
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        int num0 = 0;
        for (int i = 1; i <= n; ++i)
        {
            for (int j = 1; j <= n; ++j)
            {
                cin >> g[i][j];
                g[i + n][j] = g[i][j];
                g[i][j + n] = g[i][j];
                g[i + n][j + n] = g[i][j];
                if (g[i][j] == '0')
                    num0++;
            }
        }
        int y = 0;
        for (int k = 1; k <= n; ++k)
        {
            int cnt = 0;
            int j = k;
            for (int i = 1; i <= n; ++i)
            {
                if (g[i][j] == '1')
                    cnt++;
                j++;
            }
            y = max(cnt, y);
        }
        cout << n * n + n - num0 - 2 * y << endl;
    }
    return 0;
}

CodeForces - 1660F1
题目传送门:https://vjudge.net/contest/535955#problem/F
题意:一个字符串只由+-号组成,长度为n,定义+和-数量相同的字符串叫做平衡字符串,先给你一个字符串,你可以进行这样的操作:将相邻两个-变为+,操作数量不限,让你求这个字符串中有多少个子集,能够通过这样的操作变为平衡字符串。1≤n≤3000,1<=t<=500
题解:直接给出规律,y代表-的个数,x代表+的个数,如果(y-x)%3==0 && y>=x,就代表它可以构成平衡字符串,因为n<3000,我们直接前缀和O(n*n)枚举

点击查看代码
#include <bits/stdc++.h>
#define Zeoy std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0)
#define all(x) (x).begin(), (x).end()
#define endl '\n'
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
const int inf = 0x3f3f3f3f;
int prez[3010] = {0};
int pref[3010] = {0};
int main(void)
{
    Zeoy;
    int t;
    cin >> t;
    while (t--)
    {
        int n;
        cin >> n;
        string s;
        cin >> s;
        s = "*" + s;
        for (int i = 1; i <= n; ++i)
        {
            prez[i] = prez[i - 1] + (s[i] == '+');
            pref[i] = pref[i - 1] + (s[i] == '-');
        }
        int ans = 0;
        for (int i = n; i >= 2; --i)
        {
            for (int j = 0; j < i; ++j)
            {
                int x = prez[i] - prez[j];
                int y = pref[i] - pref[j];
                if ((y - x) % 3 == 0 && y >= x)
                {
                    ans++;
                }
            }
        }
        cout << ans << endl;
    }
    return 0;
}

CodeForces - 1660F2
题目传送门:https://vjudge.net/contest/535955#problem/G
题意:上题hard版,1≤n≤2e5,1≤t≤1e4
题解:待补

posted @ 2022-12-29 11:41  Zeoy_kkk  阅读(34)  评论(0编辑  收藏  举报