A-小红的 01 背包

思路:

  • 跳过

以下是代码部分

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

int main()
{
    int v, x, y;
    cin >> v >> x >> y;
    cout << v / x * y << endl;

    return 0;
}

B-小红的 dfs

思路:

  • 总共三种情况
  • 枚举即可

以下是代码部分

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

string s[3];

int min_modify()
{
    string target = "dfs";
    int min_changes = INT_MAX;
    int cnt = 0;
    for(int i = 0; i < 3; i ++)
    {
        if(s[i][0] != target[i])
            cnt ++;
        if(s[0][i] != target[i] && i != 0)
            cnt ++;
    }
    min_changes = min(cnt, min_changes);
    cnt = 0;
    for(int i = 0; i < 3; i ++)
    {
        if(s[i][1] != target[i])
            cnt ++;
        if(s[1][i] != target[i] && i != 1)
            cnt ++;
    }
    min_changes = min(cnt, min_changes);
    cnt = 0;
    for(int i = 0; i < 3; i ++)
    {
        if(s[i][2] != target[i])
            cnt ++;
        if(s[2][i] != target[i] && i != 2)
            cnt ++;
    }
    min_changes = min(cnt, min_changes);
    return min_changes;
}

int main()
{
    for (int i = 0; i < 3; i++) cin >> s[i];

    int result = min_modify();
    cout << result << endl;
    return 0;
}

C-小红的排列生成

思路:

  • 先从小到大排序,累加差值即可
  • 要达到全排列,只需要做到最小值匹配全排列的最小值,第二小值匹配全排列第二小值,以此类推即可

以下是代码部分

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

typedef long long ll;
const int N = 1e5 + 10;
int a[N];

int main()
{
    int n; cin >> n;
    for(int i = 1; i <= n; i ++)
        cin >> a[i];
    sort(a + 1, a + n + 1);
    ll ans = 0;
    for(int i = 1; i <= n; i ++)
    {
        if(a[i] != i)
            ans += abs(a[i] - i);
    }
    cout << ans << '\n';
    
    return 0;
}

D-小红的二进制树

题目大意:

  • 这里翻车了,看了半天不知道啥意思
  • 节点的子树,不包括节点本身, 所有的奇数组合。

思路:

  • 树形

以下是代码部分

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

const int N = 1e5 + 10;
vector<int> mp[N];
int dp[N];
string s;
//dfs深搜
void dfs(int u, int father)
{
  //赋初值
    dp[u] = (s[u] == '1');
    for(int x : mp[u])
    {
        if(x == father) continue;
        dfs(x, u);
      //每次记得相加,传递状态
        dp[u] += dp[x];
    }
}

int main()
{
    int n;
    cin >> n >> s;
  //保持下标一致
    s = '$' + s;
  //建立邻接表
    for(int i = 1, a, b; i < n; i ++)
    {
        cin >> a >> b;
        mp[a].push_back(b);
        mp[b].push_back(a);
    }
  //深搜
    dfs(1, -1);
  //遍历输出
    for(int i = 1; i <= n; i ++)
        cout << (dp[i] - s[i] + '0') << '\n';

    return 0;
}

E-小红的回文数

思路:

  • 通过类似于前缀和的方式,判断该段区间是否合法

以下是代码部分,代码参考来源——官方视频题解

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

typedef long long ll;
string s;
map<vector<int>, int> m;
vector<int> temp(10);

int main()
{
    ios::sync_with_stdio(false);
    cin >> s;
    int len = (int)s.length();
    m[temp] ++;
    ll sum = 0;
    for(int i = 0; i < len; i ++)
    {
        temp[s[i] - '0'] ^= 1;//此数字多出现一次时,偶数变奇数,奇数变偶数
        //若出现的数字次数均为偶数时
        sum += m[temp];// 若此种奇偶情况之前出现过,则必然有合法区段,统计加入
        //若只有一个数字出现的次数为奇数,其他均为偶数时
        for(int j = 0; j < 10; j ++)
        {
            vector<int> tt = temp;
            tt[j] ^= 1;
            sum += m[tt];
        }
        //更新出现次数
        m[temp] ++;
    }
    cout << sum;

    return 0;
}
  • 原理相同

以下是代码部分, 代码参考来源——tiger2005

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

typedef long long ll;
string s;
//分奇偶,共有10个数字, 2 ^ 10 = 1024, 因为为0-9,所以肯定足够
vector<int> mp(1024);

int main()
{
    ios::sync_with_stdio(false);
    cin >> s;
    //统计最后答案数
    ll sum = 0;
    int cnt = 0;
    mp[cnt] ++;
    for(auto x : s)
    {
        x -= '0';
        cnt ^= (1 << x);
        sum += mp[cnt];
        mp[cnt] ++;
        for(int i = 0; i < 10; i ++)
            sum += mp[cnt ^ (1 << i)];
    }
    cout << sum << '\n';

    return 0;
}

F-小红的矩阵修改

思路:

  • 状压dp

以下是代码部分,代码参考来源——官方视频题解

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

typedef long long ll;
int dp[1010][100]; //dp[i][j] 代表前i列,第i列的状态值为j的合法方案数。
/*
 * red : 012
 * 000
 */
string s[4];
int n, m;
int p3[5] = {1, 3, 9, 27, 81};
int a[4];

bool check(int x)
{
    for(int i = 0; i < n; i ++)
        a[i] = x % 3, x /= 3;
    for(int i = 1; i < n; i ++)
        if(a[i] == a[i - 1])
            return false;
    return true;
}
bool check(int x, int y)
{
    for(int i = 0; i < n; i ++)
    {
        if(x % 3 == y % 3)
            return false;
        x /= 3, y /= 3;
    }
    return true;
}

map<char, int>mp;

int main()
{
    int res = INT_MAX;
    mp['r'] = 0;
    mp['e'] = 1;
    mp['d'] = 2;
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    //输入n行, m列
    cin >> n >> m;
    //输入初始地图
    for(int i = 0; i < n; i ++) cin >> s[i];
    //初始化为正无穷
    memset(dp, 0x3f, sizeof dp);
    for(int i = 0; i < m; i ++)
    {
        //在第一列的情况下
        if(!i)
        {
            //每一种情况
            for(int j = 0; j < p3[n]; j ++)
                //检查该种状态下,是否合法
                if(check(j))
                {
                    int cnt = 0;
                    //判断是否修改过,统计修改次数
                    for(int k = 0; k < n; k ++)
                        if(a[k] != mp[s[k][i]])
                            cnt ++;
                    //比较,存储更小的修改次数
                    dp[0][j] = min(dp[0][j], cnt);
                }
        }
        //不是第一列时
        else
        {
            for(int j = 0; j < p3[n]; j ++)
                //判断该种状压下列与列是否合法
                if(check(j))
                {
                    int cnt = 0;
                    //如果进行了修改,则统计
                    for(int k = 0; k < n; k ++)
                        if(a[k] != mp[s[k][i]])
                            cnt ++;
                    //判断j能否由k推出来
                    //这一列能否由上一列推出来
                    for(int k = 0; k < p3[n]; k ++)
                        if(check(j, k))
                            dp[i][j] = min(dp[i][j], dp[i - 1][k] + cnt);
                }
        }
        if(i == m - 1)
            for(int j = 0; j < p3[n]; j ++)
                res = min(res, dp[i][j]);
    }
    cout << res << '\n';

    return 0;
}