蓝桥杯集训·每日一题Week1

news2024/11/28 11:41:19

前缀和(Monday)

AcWing 3956. 截断数组(每日一题)

在这里插入图片描述
思路:

首先可以预处理出前缀和。判断数组长度如果小于 3 3 3 或者前 n n n 项不是 3 3 3 的倍数,则可以直接输出 0 0 0
否则就枚举所有 s [ i ] = s [ n ] 3 s[i] = \cfrac{s[n]}{3} s[i]=3s[n],以及 s [ i ] = 2 s [ n ] 3 s[i] = \cfrac{2s[n]}{3} s[i]=32s[n] 的点,统计数量再相乘,最后输出即可。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/3/10 9:25
 */
public class Main {

    static final int N = 100010;
    static int[] s = new int[N];
    static int n;
    static long res;

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer in = new StreamTokenizer(br);
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    public static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

    public static void main(String[] args) throws IOException {
        n = nextInt();
        for (int i = 1; i <= n; i++) {
            s[i] = nextInt();
            s[i] += s[i - 1];
        }

        int cnt = 0;
        if (n < 3 || s[n] % 3 != 0) {
            out.println(0);
        } else {
            for (int i = 2; i <= n - 1; i++) {
                if (s[i - 1] == s[n] / 3) cnt++;
                if (s[i] == s[n] * 2 / 3) res += cnt;
            }
            out.println(res);
        }
        out.flush();
    }

}

AcWing 795. 前缀和

在这里插入图片描述
思路:
前缀和以 O ( 1 ) O(1) O(1) 的复杂度求出一段区间的和。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 9:10
 */
public class Main {
    static final int N = 100005;
    static int n, m;
    static int[] a = new int[N], s = new int[N];

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        String[] nm = in.readLine().split(" ");
        n = Integer.parseInt(nm[0]);
        m = Integer.parseInt(nm[1]);

        String[] arr = in.readLine().split(" ");
        for (int i = 1; i <= n; i++) {
            a[i] = Integer.parseInt(arr[i - 1]);
            s[i] = a[i] + s[i - 1];
        }

        while (m-- != 0) {
            int l, r;
            String[] lr = in.readLine().split(" ");
            l = Integer.parseInt(lr[0]);
            r = Integer.parseInt(lr[1]);
            out.println(s[r] - s[l - 1]);
        }
        out.flush();
    }
}

AcWing 796. 子矩阵的和

在这里插入图片描述
代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 9:22
 */
public class Main {
    static final int N = 1005;
    static int n, m, q;
    static int[][] s = new int[N][N];
    
    public static void main(String[] args) throws IOException {

        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        String[] nm = in.readLine().split(" ");
        n = Integer.parseInt(nm[0]);
        m = Integer.parseInt(nm[1]);
        q = Integer.parseInt(nm[2]);
        
        for (int i = 1; i <= n; i++) {
            String[] sub = in.readLine().split(" ");
            for (int j = 1; j <= m; j++) {
                s[i][j] = Integer.parseInt(sub[j - 1]);
            }
        }
        
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
            }
        }
        
        while (q-- != 0) {
            int x1, y1, x2, y2;
            String[] idx = in.readLine().split(" ");
            x1 = Integer.parseInt(idx[0]);
            y1 = Integer.parseInt(idx[1]);
            x2 = Integer.parseInt(idx[2]);
            y2 = Integer.parseInt(idx[3]);
            out.println(s[x2][y2] - s[x1 - 1][y2] - s[x2][y1 - 1] + s[x1 - 1][y1 - 1]);
        }
        out.flush();
    }
}

AcWing 99. 激光炸弹

在这里插入图片描述
思路:

典型的子矩阵的和的问题,首先对输入的 R R R 的范围进行限制, R = m i n ( R , 5001 ) R = min(R, 5001) R=min(R,5001),接着初始化子矩阵的和。接着枚举在 R × R R × R R×R 的范围内,价值的最大值。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 11:29
 */
public class Main {
    static final int N = 5002;
    static int[][] s = new int[N][N];
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        String[] nr = in.readLine().split(" ");
        int n = Integer.parseInt(nr[0]), r = Integer.parseInt(nr[1]);
        r = Math.min(5001, r);

        for (int i = 1; i <= n; i++) {
            String[] t = in.readLine().split(" ");
            int x = Integer.parseInt(t[0]), y = Integer.parseInt(t[1]), w = Integer.parseInt(t[2]);
            s[x + 1][y + 1] += w;
        }

        for (int i = 1; i <= 5001; i++) {
            for (int j = 1; j <= 5001; j++) {
                s[i][j] += s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
            }
        }

        int max = 0;

        for (int i = r; i < N; i++) {
            for (int j = r; j < N; j++) {
                max = Math.max(s[i][j] - s[i - r][j] - s[i][j - r] + s[i - r][j - r], max);
            }
        }
        out.println(max);
        out.flush();
    }
}

AcWing 1230. K倍区间

在这里插入图片描述
思路:

暴力做即使加上前缀和的优化也需要 O ( N 2 ) O(N^2) O(N2) 的时间复杂度,在本题的规模下要超时,因此需要独辟蹊径。

容易想到,如果两个数模 n n n 同余,那么这两个数的差值是 n n n 的倍数。所以可以记录前缀和模 k k k 的余数,计算余数相同的前缀和的个数,任选两个前缀和的差值即为 k k k 的倍数,这样只用 O ( N ) O(N) O(N) 的时间复杂度就可以计算出 K K K 倍区间的数目。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 11:04
 */
public class Main {
    static final int N = 100005;
    static int[] s = new int[N];
    static int[] mod = new int[N];
    static long ans;
    static int n, k;
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        String[] nk = in.readLine().split(" ");
        n = Integer.parseInt(nk[0]);
        k = Integer.parseInt(nk[1]);

		// 余数为0先赋值为1,当区间和为前缀和时,需要用到
        mod[0] = 1;
        for (int i = 1; i <= n; i++) {
            s[i] = Integer.parseInt(in.readLine().split(" ")[0]);
            s[i] += s[i - 1];
            s[i] %= k;
            mod[s[i]]++;
        }

        for (int i = 0; i <= k - 1; i++) {
            ans += (long) mod[i] * (mod[i] - 1) / 2;
        }
        out.println(ans);
        out.flush();
    }
}

差分(Tuesday)

AcWing 3729. 改变数组元素(每日一题)

在这里插入图片描述
思路:

分析只,只要执行一次操作 2 2 2,数组元素都会变为 1 1 1,所以可以用差分构造每个数的操作 2 2 2 的次数,如果大于 1 1 1,该数就为 1 1 1

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Arrays;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/28 14:21
 */
public class Main {

    static final int N = 200005;
    static int t, n;
    // b记录操作的次数
    static int[] b = new int[N];

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        String T = in.readLine().split(" ")[0];
        t = Integer.parseInt(T);

        while (t-- != 0) {
            
            Arrays.fill(b, 0);
            String s = in.readLine().split(" ")[0];
            n = Integer.parseInt(s);
            String[] arr = in.readLine().split(" ");
            int x;
            for (int i = 1; i <= n; i++) {
                x = Integer.parseInt(arr[i - 1]);
                if (x == 0) continue;
                else if (x <= i) {
                    insert(i - x + 1, i, 1);
                }
                else insert(1, i, 1);
            }
            
            for (int i = 1; i <= n; i++) {
                b[i] += b[i - 1];
                out.print((b[i] > 0 ? 1 : 0) + " ");
            }
            out.println();
            out.flush();

            
        }
    }

    public static void insert(int l, int r, int c) {
        b[l] += c;
        b[r + 1] -= c;
    }
}

AcWing 797. 差分

在这里插入图片描述

给区间[l, r]中的每个数加上c:B[l] += c, B[r + 1] -= c
#include<iostream>
using namespace std;

const int N = 1e6 + 5;
int a[N], q[N];

void insert(int l, int r, int c)
{
    b[l] += c;
    b[r + 1] -= c;
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    //构造差分数组b
    for (int i = 1; i <= n; i++)
        insert(i, i, a[i]);
    while (m --)
    {
        int l, r, c;
        scanf("%d%d%d", &l, &r, &c);
        insert(l, r, c);
    }
    for (int i = 1; i <= n; i++)
        b[i] += b[i - 1];
    for (int i = 1; i <= n; i++)
        printf("%d ", b[i]);
    return 0;
}

AcWing 798. 差分矩阵

在这里插入图片描述

给以(x1, y1)为左上角,(x2, y2)为右下角的子矩阵中的所有元素加上c:
S[x1, y1] += c, S[x2 + 1, y1] -= c, S[x1, y2 + 1] -= c, S[x2 + 1, y2 + 1] += c
#include<iostream>
using namespace std;
const int N = 100010;
int n, m, q;
int a[N][N], b[N][N];
void insert(int x1, int y1, int x2, int y2, int c)
{
    b[x1][y1] += c;
    b[x2][y1 + 1] -= c;
    b[x1][y2 + 1] -= c;
    b[x2 + 1][y2 + 1] += c;
}
int main()
{
    cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            cin >> a[i][j];
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            insert(i, j, i, j, a[i][j]);
    while (q--)
    {
        int x1, y1, x2, y2, c;
        cin >> x1 >> y1 >> x2 >> y2 >> c;
        insert(x1, y1, x2, y2, c);
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++)
            b[i][j] += b[i][j - 1] + b[i - 1][j] - b[i - 1][j - 1];
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cout << b[i][j] << ' ';
        }
        cout << endl;
    }
    return 0;    
}

二分(Wednesday)

AcWing 1460. 我在哪?(每日一题)

在这里插入图片描述
思路:

本质上是一个寻找最短的不重复子串的问题,可以二分枚举子串的长度。构造子串可以用字符串哈希或者 substring(int fromIndex, int toIndex) 方法,数据范围大的话,建议用字符串哈希。

二分 + 字符串哈希:

核心思想: 将字符串看成P进制数,P的经验值是131或13331,取这两个值的冲突概率低
小技巧: 取模的数用 2 64 2^{64} 264,这样直接用 unsigned long long存储,溢出的结果就是取模的结果
注意: 字符串从 1 1 1 的位置开始存。前 l l l 位字符串的哈希值是 h [ l ] h[l] h[l],前 r r r 位字符串的哈希值是 h [ r ] h[r] h[r],则 l ∼ r l \sim r lr 之间字符串(包含端点)的哈希值可以表示为:
h [ l ∼ r ] = h [ 1 ∼ r ] − h [ 1 ∼ l − 1 ] ∗ P r − l + 1 \begin{aligned} h[l \sim r] &= h[1 \sim r] - h[1 \sim l - 1] * P ^{r - l + 1} \end{aligned} h[lr]=h[1r]h[1l1]Prl+1

在这里插入图片描述

在这里插入图片描述

模板

typedef unsigned long long ull;
ull h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64

// 初始化
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{
    h[i] = h[i - 1] * P + str[i];
    p[i] = p[i - 1] * P;
}

// 计算子串 str[l ~ r] 的哈希值
ull get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}
#include <iostream>
#include <set>
using namespace std;

typedef unsigned long long ull;

const int N = 105, P = 131;
ull h[N], p[N];
char str[N];
int n;
set<ull> res;

ull get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}

bool check(int mid) 
{
    res.clear();
    for (int i = 1; i + mid - 1 <= n; i++)
    {
        ull t = get(i, i + mid - 1);
        if (res.find(t) != res.end()) return false;
        res.insert(t);
    }
    
    return true;
}

int main()
{
    cin >> n;
    cin >> str + 1;
    
    p[0] = 1;
    
    for (int i = 1; i <= n; i++) 
    {
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + str[i];
    }
    
    int l = 1, r = 101;
    
    // 此模板用于求最小方案
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    
    cout << l << endl;
    return 0;
}

AcWing 789. 数的范围

在这里插入图片描述
思路:

二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。

版本1
当我们将区间[l, r]划分成[l, mid][mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。

版本2
当我们将区间[l, r]划分成[l, mid - 1][mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。

二分查找时,如果满足当前的 check() 函数,则继续二分。当查找数的左边界时,check() 函数 为 a[mid] >= x,满足条件时,需要更新右边界,r = mid,否则更新左边界 l = mid + 1,此时将区间[l, r]划分成[l, mid][mid + 1, r],用的是第一版本的二分, mid = l + r >> 1

当查找数的右边界时,check() 函数 为 a[mid] <= x,满足条件时,需要更新左边界,l = mid,否则更新右边界 r = mid - 1,此时将区间[l, r]划分成[l, mid - 1][mid, r],用的是第二版本的二分,mid = l + r + 1 >> 1

如果第一轮二分的结果,a[l] != x || a[r] != x,则不存在 x,此时输出 -1 - 1 即可。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 8:05
 */
public class Main {
    static final int N = 100005;
    static int[] a = new int[N];
    static int n, q, k;

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        String[] s = in.readLine().split(" ");
        n = Integer.parseInt(s[0]);
        q = Integer.parseInt(s[1]);

        String[] arr = in.readLine().split(" ");
        for (int i = 0; i < n; i++) a[i] = Integer.parseInt(arr[i]);

        while (q-- != 0) {
            int x = Integer.parseInt(in.readLine());
            int l = 0, r = n - 1;

            while (l < r) {
                int mid = l + r >> 1;
                if (a[mid] >= x) r = mid;
                else l = mid + 1;
            }

            if (a[l] != x) out.println("-1 -1");
            else {
                out.print(l + " ");
                l = 0;
                r = n - 1;

                while (l < r) {
                    int mid = l + r + 1 >> 1;
                    if (a[mid] <= x) l = mid;
                    else r = mid - 1;
                }

                out.print(r + "\n");
            }
        }
        out.flush();
    }
}

另外,使用 BufferedReaderPrintWriter 替换 ScannerSystem.out.println()输入输出后,性能有了较大的飞跃。

在这里插入图片描述

AcWing 790. 数的三次方根

在这里插入图片描述
思路:

浮点数二分,最后的精度要求要比给定的要再精确两位。比如结果要求6位小数,则 eps = 1e-8。更新左右边界是将 mid 的值赋值给左右边界,当左右边界的差值小于 精度 eps 时,就结束二分。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 9:02
 */
public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        double n = Double.parseDouble(in.readLine());
        double eps = 1e-8;
        double l = -10000, r = 10000;

        while (r - l > eps) {
            double mid = (l + r) / 2;
            if (mid * mid * mid >= n) r = mid;
            else l = mid;
        }

        out.printf("%.6f", l);
        out.flush();
    }
}

AcWing 1227. 分巧克力

在这里插入图片描述
思路:

二分枚举边长的最大值,如果当前边长满足条件,更新左边界 l = mid,否则更新右边界 r = mid - 1,用的是第二个二分模板。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/25 10:14
 */
public class Main {
    static final int N = 100005;
    static int[] h = new int[N], w = new int[N];

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        String[] nk = in.readLine().split(" ");
        int n = Integer.parseInt(nk[0]);
        int k = Integer.parseInt(nk[1]);
        int sq = 0;

        for (int i = 0; i < n; i++) {
            String[] s = in.readLine().split(" ");
            h[i] = Integer.parseInt(s[0]);
            w[i] = Integer.parseInt(s[1]);
        }

        int ans = 0;

        int l = 1, r = 100001;

        while (l < r) {
            long num = 0;
            int mid = l + r + 1>> 1;
            for (int i = 0; i < n; i++) {
                num += (long)h[i] / mid * (w[i] / mid);
            }
            if (num >= k) {
                l = mid;
            }
            else r = mid - 1;
        }

        out.println(l);
        out.flush();
    }
}

双指针(Thursday)

AcWing 3768. 字符串删减(每日一题)

在这里插入图片描述
思路:

双指针 i i i j j j 分别记录连续的 x . . . x... x... 子串的开始与结尾,统计重复字串的长度,减到长度为 2 2 2 即可,不够 3 3 3 可以不用减。

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/3/3 14:01
 */
public class Main {
    public static void main(String[] args) throws IOException{
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        int n = Integer.parseInt(in.readLine());
        String s = in.readLine();

        int ans = 0;
        for (int i = 0; i < n; i++) {
            
            // 求连续的x的长度
            if (s.charAt(i) == 'x') {
                int j = i + 1;
                while (j < n && s.charAt(j) == 'x') j++;
                ans += Math.max(j - i - 2, 0);
                i = j;
            }
        }

        out.println(ans);
        out.flush();
    }
}

AcWing 799. 最长连续不重复子序列

在这里插入图片描述

#include <iostream>
using namespace std;

const int N = 100005;
int cnt[N], a[N];
int n;

int main()
{
    cin >> n;
    int res = 0;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0, j = 0; i < n; i++)
    {
        // i为终点,j为起点
        cnt[a[i]]++;
        // 遇到重复的元素 j往后移 同时重复的元素的个数-1
        while (cnt[a[i]] > 1) cnt[a[j++]]--;
        // 枚举从起点到终点的距离的最大值
        res = max(res, i - j + 1);
    }
    cout << res;
    return 0;
}

AcWing 800. 数组元素的目标和

在这里插入图片描述

#include <iostream>
using namespace std;
const int N = 100005;
int a[N], b[N];

int main()
{
    int n, m, x;
    cin >> n >> m >> x;
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int j = 0; j < m; j++) cin >> b[j];
    
    int i = 0, j = m - 1;
    //从两端枚举
    while (i < n && j >= 0)
    {
        // 和大于x, j向前移动
        while (a[i] + b[j] > x) j--;
        // 和小于x, i向后移动
        while (a[i] + b[j] < x) i++;
        if (a[i] + b[j] == x) 
        {
            cout << i << ' ' << j;
            break;
        }
    }
    
    return 0;
}

递推(Friday)

AcWing 3777. 砖块(每日一题)

在这里插入图片描述
思路:

首先,如果两种颜色的砖块都是奇数个数,则无法通过翻转变成同一种颜色,如果只有一种颜色,则不用翻转。

可以分两种情况。

  • 都翻转成白色。遇到黑的就翻转,最后判断最后一个砖块是不是白色
  • 都翻转成黑色。遇到白的就翻转,最后判断最后一个砖块是不是黑色

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.StreamTokenizer;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/3/6 9:18
 */
public class Main {

    static int T, n;

    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static StreamTokenizer in = new StreamTokenizer(br);
    static PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

    public static int nextInt() throws IOException {
        in.nextToken();
        return (int) in.nval;
    }

    public static void main(String[] args) throws IOException {
        T = nextInt();

        while (T-- != 0) {
            n = nextInt();
            int a = 0, b = 0;
            int[] p1 = new int[205];
            int[] p2 = new int[205];
            int[] d1 = new int[205];
            int[] d2 = new int[205];
            int cnt1 = 0, cnt2 = 0;
            String s = br.readLine();
            // 0白 1黑
            for (int i = 0; i < n; i++) {
                if (s.charAt(i) == 'W') {
                    d1[i] = 0;
                    d2[i] = 0;
                    a++;
                } else {
                    d1[i] = 1;
                    d2[i] = 1;
                    b++;
                }
            }

            if (a % 2 == 1 && b % 2 == 1) out.println(-1);
            else if (a == 0 || b == 0) out.println(0);
            else {
                for (int i = 0; i < n - 1; i++) {
                    // 都换成白的
                    if (d1[i] == 1) {
                        d1[i] = 0;
                        d1[i + 1] = 1 - d1[i + 1];
                        p1[cnt1++] = i + 1;
                    }
                }

                for (int i = 0; i < n - 1; i++) {
                    // 都换成黑的
                    if (d2[i] == 0) {
                        d2[i] = 1;
                        d2[i + 1] = 1 - d2[i + 1];
                        p2[cnt2++] = i + 1;
                    }
                }

                if (d1[n - 1] != 0) {
                    out.println(cnt2);
                    for (int i = 0; i < cnt2; i++) out.printf("%d ", p2[i]);
                    out.println();
                } else {
                    out.println(cnt1);
                    for (int i = 0; i < cnt1; i++) out.printf("%d ", p1[i]);
                    out.println();
                }
            }
        }
        out.flush();
    }
}

AcWing 95. 费解的开关

在这里插入图片描述

思路:

考虑第一行,有 2 n 2 ^ n 2n 种不同的状态。对于第一行的每个灯的状态,由于每个开关状态的改变会影响上下左右的所有开关的状态,所以在第一行,如果某灯是灭的话,有且仅有该灯下面第二行的开关的改变能影响该灯的状态,也就是说,只有正下方的开关可以改变上一层的状态,第 n n n 行 确定 n + 1 n + 1 n+1 行的状态,第一行确定整个的状态,所以只需要用二进制枚举第一行的状态即可,判断最后一行是否都为亮的,如果都是亮的,则有可行解,再判断可行解与 6 的 关系。

为保证不同的操作方式之间的结果不干扰,一开始要对原始数组先备份,然后再还原。

代码:

import java.util.Arrays;
import java.util.Scanner;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/23 15:46
 */
public class Main {

    static final int N = 6;
    static char[][] g = new char[N][N], backup = new char[N][N];
    static int n;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        n = scanner.nextInt();

        while (n-- != 0) {

            for (int i = 0; i < 5; i++) {
                String s = scanner.next();
                g[i] = s.toCharArray();
            }

            int res = 10;


            for (int op = 0; op < (1 << 5); op++) {

                for (int j = 0; j < 5; j++) {
                    backup[j] = Arrays.copyOf(g[j], 5);
                }

                int step = 0;

                for (int i = 0; i < 5; i++) {
                    if ((op >> i & 1) == 1) {
                        step++;
                        turn(0, i);
                    }
                }

                for (int i = 0; i < 4; i++) {
                    for (int j = 0; j < 5; j++) {
                        if (g[i][j] == '0') {
                            step++;
                            turn(i + 1, j);
                        }
                    }
                }
                boolean flag = false;

                for (int i = 0; i < 5; i++) {
                    if (g[4][i] == '0') {
                        flag = true;
                        break;
                    }
                }

                if (!flag) res = Math.min(res, step);
                for (int j = 0; j < 5; j++) {
                    g[j] = Arrays.copyOf(backup[j], 5);
                }

            }

            if (res > 6) System.out.println(-1);
            else System.out.println(res);
        }

    }


    public static void turn(int x, int y) {
        int[] dx = {-1, 1, 0, 0, 0}, dy = {0, 0, -1, 1, 0};

        for (int i = 0; i < 5; i++) {
            int a = x + dx[i], b = y + dy[i];
            if (a < 0 || a >= 5 || b < 0 || b >= 5) continue;
            g[a][b] ^= 1;
        }
    }
}

AcWing 116. 飞行员兄弟

在这里插入图片描述
思路:

因为本题规模不大,所以可以通过枚举和位运算来求解,一共有 16 个位置,则有 2 16 = 65536 2^{16} = 65536 216=65536 种状态,最后判断开关的状态。用ArrayList 来存储操作,仅当操作数更少的时候,才更新操作集。

代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/23 16:48
 */
public class Main {
    static final int N = 5;
    static char[][] g = new char[N][N], backup = new char[N][N];

    static class Node {
        int x, y;

        Node(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Node> ans = new ArrayList<>();
        for (int i = 0; i < 4; i++) {
            String s = scanner.next();
            g[i] = s.toCharArray();
        }

        for (int op = 0; op < (1 << 16); op++) {

            for (int j = 0; j < 4; j++) {
                backup[j] = Arrays.copyOf(g[j], g[j].length);
            }

            ArrayList<Node> tmp = new ArrayList<>();


            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
                    if (((op >> (i * 4 + j)) & 1) == 1) {
                        turn(i, j);
                        tmp.add(new Node(i, j));
                    }
                }
            }

            boolean flag = false;
            for (int i = 0; i < 4; i++) {
                for (int j = 0; j < 4; j++) {
                    if (g[i][j] == '+') {
                        flag = true;
                        break;
                    }
                }
            }

            if (!flag) {
                if (ans.isEmpty() || ans.size() > tmp.size()) ans = tmp;
            }

            for (int j = 0; j < 4; j++) {
                g[j] = Arrays.copyOf(backup[j], backup[j].length);
            }

        }

        System.out.println(ans.size());
        for (Node tmp : ans) {
            System.out.println((tmp.x + 1) + " " + (tmp.y + 1));
        }

    }

    public static void turn(int x, int y) {
        for (int i = 0; i < 4; i++) {
            g[x][i] = g[x][i] == '+' ? '-' : '+';
            g[i][y] = g[i][y] == '+' ? '-' : '+';
        }
        g[x][y] = g[x][y] == '+' ? '-' : '+';

    }
}

AcWing 1208. 翻硬币

在这里插入图片描述
思路:

本题有不超过100个元素,枚举状态会超时,可以考虑贪心来做,如果两个字符串某个相同位置的元素不相同,就翻转,操作的次数就加一。这样只需要用到 O ( N ) O(N) O(N) 的时间复杂度。

代码:

import java.util.Scanner;

/**
 * @Description
 * @Author: PrinceHan
 * @CreateTime: 2023/2/24 9:54
 */
public class Main {
    static final int N = 105;
    static char[] s1 = new char[N], s2 = new char[N];
    static String start, end;
    static int n, ans;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        start = scanner.next();
        end = scanner.next();
        n = start.length();
        s1 = start.toCharArray();
        s2 = end.toCharArray();

        for (int i = 0; i < n - 1; i++) {
            if (s1[i] != s2[i]) {
                ans++;
                turn(i);
            }
        }

        System.out.println(ans);

    }

    public static void turn(int u) {
        s1[u] = s1[u] == '*' ? 'o' : '*';
        s1[u + 1] = s1[u + 1] == '*' ? 'o' : '*';
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/402287.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

kali双网卡

先单独开启一个网卡&#xff0c;配置/etc/network/interfaces 修改为如下配置 This file describes the network interfaces available on your system and how to activate them. For more information, see interfaces(5). source /etc/network/interfaces.d/* The loopb…

JVM系列——Java与线程,介绍线程原理和操作系统的关系

并发不一定要依赖多线程(如PHP中很常见的多进程并发)。 但是在Java里面谈论并发&#xff0c;基本上都与线程脱不开关系。因此我们讲一下从Java线程在虚拟机中的实现。 线程的实现 线程是比进程更轻量级的调度执行单位。 线程的引入&#xff0c;可以把一个进程的资源分配和执行调…

【深度强化学习】(3) Policy Gradients 模型解析,附Pytorch完整代码

大家好&#xff0c;今天和各位分享一下基于策略的深度强化学习方法&#xff0c;策略梯度法是对策略进行建模&#xff0c;然后通过梯度上升更新策略网络的参数。我们使用了 OpenAI 的 gym 库&#xff0c;基于策略梯度法完成了一个小游戏。完整代码可以从我的 GitHub 中获得&…

原型模式(设计模式详解)

原型模式 描述 原型模式&#xff08;Prototype Pattern&#xff09;是一种创建型设计模式&#xff0c;它允许通过复制现有对象来创建新对象&#xff0c;而无需从头开始编写代码。 在原型模式中&#xff0c;一个原型对象作为模板&#xff0c;新的对象通过克隆这个原型对象而创…

MySQL OCP888题解048-letter N in slow query log(慢查询日志里的字母N)

文章目录1、原题1.1、英文原题1.2、中文翻译1.3、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3.1、知识点1&#xff1a;mysqldumpslow - 总结缓慢的查询日志文件4、实验4.1、实验14.1.1、实验目的4.1.2、实验前准备4.1.3、实验步骤4.1.4、实验结论5、总结1、原题 1.1…

dva01-初识

背景 React 本身只是一个 DOM 的抽象层&#xff0c;使用组件构建虚拟 DOM。如果开发大应用&#xff0c;还需要解决一个问题。 通信&#xff1a;React 只提供了一种传参手段&#xff0c;后续数据变化非常麻烦&#xff0c;无法适用于大应用。数据流&#xff1a;每次要更新数据&…

ACE C++网络通信框架深入解析ACE_Message_Block消息类

前言 我所见到最好消息包的接口设计莫过于ACE_Message_Block了。 为什么这样说呢&#xff1f; 对于它的API说明&#xff0c;我最初仅想在它的基础上提供注释说明&#xff0c;而不想多言其它&#xff0c;因为无需多言其他。 不过&#xff0c;后来还是补充两个图&#xff0c;以…

后台搭建常用方式及常用的插件

利用脚手架创建项目 create-vite 是一个快速生成主流框架基础模板的工具,安装后启动预设创建项目 使用NPM&#xff1a; npm create vitelatest 使用Yarn: yarn create vite 使用PNPM: pnpm create vite 开始 | Vite 官方中文文档 create-vue&#xff0c;是 Vue 官方的项目脚…

Flume工作原理 安装配置

目录 简介 主要功能 日志收集 数据处理 工作原理 Flume架构 安装 拷贝压缩包 解压 改名 修改配置文件 安装nc&#xff08;netcat&#xff09; 安装telnet协议 应用 应用一&#xff1a;实时监听 新建netcat-logger.conf文件 开启端口监听方式一 访问主机 开启…

flume安装与配置

目录 flume描述 flume用途 flume基本组件 配置flume 搭建环境&#xff1a; 解压flume安装包将其放入到opt/soft目录 在/opt/soft目录下将apache-flume-1.9.0-bin.tar.gz 改名为flume190 到/opt/soft/flume190/conf目录中将临时配置文件flume-env.sh.template拷贝为配置文…

香港酒店模拟分析项目报告--使用tableau、python、matlab

转载请标记本文出处 软件&#xff1a;tableau、pycharm、关系型数据库&#xff1a;MySQL 数据大量分析考虑电脑性能的情况。 文章目录前言一、爬虫是什么&#xff1f;二、使用tableau数据可视化1.引入数据1.1 制作直方图-各地区酒店数量条形图1.2 各地区酒店均价1.3 价格等级堆…

Idea+maven+spring-cloud项目搭建系列--11-3 dubbo限流和熔断

前言: dubbo 作为rpc 通信组件&#xff0c;在使用过程中&#xff0c;如何避免服务提供端被多个消费端撑爆&#xff0c;消费端如何避免因为服务端的故障造成结果响应超时。 1 服务提供端的限流措施&#xff1a; 1.1 使用 &#xff1a;dubbo.protocol.accepts 参数限制服务端同…

面试热点题:回溯算法之组合 组合与组合总和 III

什么是回溯算法&#xff1f; 回溯算法也可以叫回溯搜索算法&#xff0c;回溯是递归的"副产品",回溯的本质是穷举&#xff0c;然后选出我们需要的数据&#xff0c;回溯本身不是特别高效的算法&#xff0c;但我们可以通过"剪枝"来优化它。 理解回溯算法 回溯…

电脑游戏怎么录屏?其实很简单,只需要简单3步

电脑游戏一直是游戏爱好者最热衷的游戏之一。但是&#xff0c;有时候我们想分享我们在游戏中的精彩时刻&#xff0c;或者记录我们的游戏过程以便后续观看和学习。在这种情况下&#xff0c;录屏就成了必不可少的工具。但是&#xff0c;许多人可能不知道电脑游戏怎么录屏。在本文…

逆向分析——壳

你脑海中的壳是什么 壳在自然界是动物的保护壳&#xff0c;软件同样有保护壳&#xff0c;为了防止破解 也许大海给贝壳下的定义是珍珠&#xff0c;也许时间给煤炭下的定义是钻石 ——沙与沫 壳的由来 在DOS时代&#xff0c;壳一般指的是磁盘加密软件中的一段加密程序 后来发展…

APM新添加UAVCAN设备

简介 UAVCAN是一种轻量级协议,旨在通过CAN总线在航空航天和机器人应用中实现可靠通信。要实现通信&#xff0c;最基本需要data_type_ id, signature、数据结构、设备程序初始化。 添加设备数据结构文件(.uavcan格式) 1.在以下路径添加设备数据结构文件&#xff0c;根据设备类…

三体到底是啥?用Python跑一遍就明白了

文章目录拉格朗日方程推导方程组微分方程算法化求解画图动图绘制温馨提示&#xff0c;只想看图的画直接跳到最后一节拉格朗日方程 此前所做的一切三体和太阳系的动画&#xff0c;都是基于牛顿力学的&#xff0c;而且直接对微分进行差分化&#xff0c;从而精度非常感人&#xf…

Web漏洞-CSRF漏洞

CSRF漏洞介绍&#xff1a;CSRF&#xff08;Cross-Site Request Forgery&#xff09;&#xff0c;中文名称&#xff1a;跨站请求伪造&#xff0c;是一种劫持用户在当前已登录的Web应用程序上执行非本意操作一种攻击.原理&#xff1a;攻击者利用目标用户的身份&#xff0c;执行某…

基于Stackelberg博弈的光伏用户群优化定价模型(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

keras学习之回调函数的使用

回调函数 回调函数是一个对象&#xff08;实现了特定方法的类实例&#xff09;&#xff0c;它在调用fit()时被传入模型&#xff0c;并在训练过程中的不同时间点被模型调用可以访问关于模型状态与模型性能的所有可用数据模型检查点&#xff08;model checkpointing&#xff09;…