牛客网编程题

一、小红的字符串(给定由19组成的数字串(不含0)和一个正整数k,求连续子串小于k的方案)

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define MAX_LEN 200010

int main() {

    char s[MAX_LEN];

    int k;

    scanf("%s", s);

    scanf("%d", &k);

    int n = strlen(s);

    // 将k转换为字符串并计算其长度

    char str_k[12];

    int len_k = sprintf(str_k, "%d", k);

    long long total = 0; // 使用 long long 避免溢出

    for (int i = 0; i < n; i++) {

        // 计算长度小于 len_k 的子串个数

        int low_len = len_k - 1;

        if (n - i < low_len) {

            low_len = n - i;

        }

        total += low_len;

        // 检查长度等于 len_k 的子串

        if (n - i >= len_k) {

            // 比较子串 s[i:i+len_k] 和 str_k

            if (memcmp(s + i, str_k, len_k) < 0) {

                total++;

            }

        }

    }

    printf("%lld\n", total);

    return 0;

}

二、小红的01(小红有01字符串【仅由字符0和字符1组成,她可以进行任意次操作,每次操作选择一个字符将其取反(01,10),求将给定字符串变成好串的最小操作次数】)

#include <stdio.h>

#include <string.h>

int min(int a, int b) {

    return a < b ? a : b;

}

int min4(int a, int b, int c, int d) {

    return min(min(a, b), min(c, d));

}

int main() {

    char s[100001];

    scanf("%s", s);

    int n = strlen(s);

    if (n == 0 || n == 1) {

        printf("0\n");

        return 0;

    }

    int last00 = (s[0] != '0') + (s[1] != '0');

    int last11 = (s[0] != '1') + (s[1] != '1');

    int last01 = (s[0] != '0') + (s[1] != '1');

    int last10 = (s[0] != '1') + (s[1] != '0');

    if (n == 2) {

        printf("%d\n", min4(last00, last11, last01, last10));

        return 0;

    }

    for (int i = 2; i < n; i++) {

        int cost0 = (s[i] != '0') ? 1 : 0;

        int cost1 = (s[i] != '1') ? 1 : 0;

        int cur00 = min(last00 + cost0, last10 + cost0);

        int cur11 = min(last11 + cost1, last01 + cost1);

        int cur01 = last00 + cost1;

        int cur10 = last11 + cost0;   

        // 更新状态

        last00 = cur00;

        last11 = cur11;

        last01 = cur01;

        last10 = cur10;

    }

    printf("%d\n", min4(last00, last11, last01, last10));

    return 0;

}

三、小红的奇偶抽取(要求将正整数n的各位数字按奇偶性分离,然后将奇数和偶数取绝对值)

#include <stdio.h>

#include <stdlib.h>

int main() {

    char s[16]; // 存储输入整数(最多15位+结束符)

    scanf("%s", s);

    long long num_odd = 0;  // 奇数组成的整数

    long long num_even = 0; // 偶数组成的整数

    for (int i = 0; s[i] != '\0'; i++) {

        int digit = s[i] - '0'; // 字符转数字

        if (digit % 2 == 1) {

            num_odd = num_odd * 10 + digit;

        } else {

            num_even = num_even * 10 + digit;

        }

    }

    // 计算差的绝对值

    long long diff = num_odd - num_even;

    if (diff < 0) {

        diff = -diff;

    }   

    printf("%lld\n", diff);

    return 0;

}

四、游游的整数切割(给定一个非常大的正整数,将其切割成两部分,求有多少种切割方式使得两部分数字的和是偶数)

#include <stdio.h>

#include <string.h>

int main() {

    char s[100001]; // 存储输入的数字字符串

    scanf("%s", s);

    int n = strlen(s);

    if (n == 1) {

        printf("0\n");

        return 0;

    }

    char last = s[n - 1]; // 最后一位字符

    long long count = 0; // 合法切割方案计数

    for (int i = 0; i < n - 1; i++) {

        if (last == '0' || last == '2' || last == '4' || last == '6' || last == '8') {

            if (s[i] == '0' || s[i] == '2' || s[i] == '4' || s[i] == '6' || s[i] == '8') {

                count++;

            }

        } else {

            if (s[i] == '1' || s[i] == '3' || s[i] == '5' || s[i] == '7' || s[i] == '9') {

                count++;

            }

        }

    }   

    printf("%lld\n", count);

    return 0;

}

五、小美走公路(环形公路,有n个站点,编号从1n,如果选择顺时针/逆时针行走,计算两个方向的最短的距离)

 

#include <stdio.h>

#include <stdlib.h>

int main() {

    int n;

    scanf("%d", &n);

    long long *a = (long long *)malloc(n * sizeof(long long));

    for (int i = 0; i < n; i++) {

        scanf("%lld", &a[i]);

    }

    int x, y;

    scanf("%d %d", &x, &y);

    long long *pre = (long long *)malloc((n + 1) * sizeof(long long));

    pre[0] = 0;

    for (int i = 0; i < n; i++) {

        pre[i + 1] = pre[i] + a[i];

    }

    long long total = pre[n];  // 总距离    

    long long clockwise;

    if (x <= y) {

        clockwise = pre[y - 1] - pre[x - 1];

    } else {

        clockwise = (total - pre[x - 1]) + pre[y - 1];

    }

    long long anticlockwise = total - clockwise;  // 逆时针距离

    long long ans = clockwise < anticlockwise ? clockwise : anticlockwise;   // 取最小值

    printf("%lld\n", ans);   

    free(a);

    free(pre);

    return 0;

}

六、小美的排列询问(给定长度为n的排列,包含1n每个整数恰好一次的数组,判断两个指定的整数x,y是否在排列中相邻)

#include <stdio.h>

#include <stdlib.h>

int main() {

    int n;

    scanf("%d", &n);

    int *arr = (int*)malloc(n * sizeof(int));

    int *pos = (int*)malloc((n + 1) * sizeof(int));

    for (int i = 0; i < n; i++) {

        scanf("%d", &arr[i]);

        pos[arr[i]] = i;  // 记录数字 arr[i] 的位置

    }

    int x, y;

    scanf("%d %d", &x, &y);

    int diff = abs(pos[x] - pos[y]);

    if (diff == 1) {

        printf("Yes\n");

    } else {

        printf("No\n");

    }

    // 释放动态分配的内存

    free(arr);

    free(pos);

    return 0;

}

七、相遇(在一条一维数轴上,有$n$个行人,每个行人有初始位置$x_i$和行走方向$a_i$,求相遇)

#include <stdio.h>

#include <stdlib.h>

typedef struct {

    int pos;

    int dir;

} Person;

int compare(const void *a, const void *b) {

    Person *p1 = (Person *)a;

    Person *p2 = (Person *)b;

    return p1->pos - p2->pos;

}

int main() {

    int n;

    scanf("%d", &n);

    Person *people = (Person *)malloc(n * sizeof(Person));

    for (int i = 0; i < n; i++) {

        scanf("%d %d", &people[i].pos, &people[i].dir);

    }

    qsort(people, n, sizeof(Person), compare);

    long long ans = 0; // 使用long long防止大数溢出

    int countRight = 0; // 记录当前已遍历的向右行走的人数

    for (int i = 0; i < n; i++) {

        if (people[i].dir == 1) {

            countRight++;

        } else {

            ans += countRight;

        }

    }

    printf("%lld\n", ans);

    free(people);

    return 0;

}

八、小红的与运算(给定一个包含n个正整数组和一个整数k,需要从中选择k个数,使得这些数的按位与运算结果尽可能大,求最大的按位与结果)

#include <stdio.h>

int main() {

    int n, k;

    scanf("%d %d", &n, &k);

    int a[n];

    for (int i = 0; i < n; i++) {

        scanf("%d", &a[i]);

    }

    int ans = 0;

    for (int bit = 30; bit >= 0; bit--) {

        int cur = ans | (1 << bit); // 尝试将当前位置1

        int cnt = 0;

        for (int i = 0; i < n; i++) {

            if ((a[i] & cur) == cur) {

                cnt++;

            }

        }

        if (cnt >= k) {

            ans = cur;

        }

    }

    printf("%d\n", ans);

    return 0;

}

九、小欧的括号操作(给定一个仅由字符()组成的字符串,小红可以进行任意次操作,每次操作都会减少一个字符,小红知道经过若干次操作后,字符串的最短长度是多少?)

#include <stdio.h>

#include <string.h>

#define MAX_SIZE 200010

char stack[MAX_SIZE];

int main() {

    char s[MAX_SIZE];

    scanf("%s", s);

    int n = strlen(s);

    int top = 0; // 栈顶指针

    for (int i = 0; i < n; i++) {

        if (s[i] == '(') {

            stack[top++] = '('; // 遇到 '(' 压栈

        } else {

            if (top > 0 && stack[top - 1] == '(') {

                top--;

                stack[top++] = '(';

            } else {

                stack[top++] = ')';             }

        }

    }

printf("%d\n", top);

return 0;

}

十、小欧的选数乘积(小欧有两个正整数x,y,以及一个包含n个正整数的数组@。每轮操作,她可以从数组中选择一个元素@i,问小欧最少需要多少轮操作,才能使x不小于y,如果无法实现,输出-1)

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <limits.h>

int cmp(const void *a, const void *b) {

    long long va = *(const long long *)a;

    long long vb = *(const long long *)b;

    if (va < vb) return 1;

    if (va > vb) return -1;

    return 0;

}

int main() {

    long long x, y;

    int n;

    scanf("%lld %lld", &x, &y);

    scanf("%d", &n);

    long long *arr = (long long *)malloc(n * sizeof(long long));

    for (int i = 0; i < n; i++) {

        scanf("%lld", &arr[i]);

    }

    if (x >= y) {

        printf("0\n");

        free(arr);

        return 0;

    }

    if (n == 0) {

        printf("-1\n");

        free(arr);

        return 0;

    }

    qsort(arr, n, sizeof(long long), cmp);

    int m = 0;

    for (int i = 0; i < n; i++) {

        if (i == 0 || arr[i] != arr[i - 1]) {

            if (arr[i] != 1) {

                arr[m++] = arr[i];

            }

        }

    }

    if (m == 0) {

        printf("-1\n");

        free(arr);

        return 0;

    }

    long long cur = x;

    int count = 0;

    for (int i = 0; i < m; i++) {

        long long a = arr[i];

        if (cur >= y) break;

        long long threshold = (y - 1) / a + 1;

        if (cur >= threshold) {

            count++;

            cur = y; // 标记已满足

            break;

        }

        if (a > 0 && cur > LLONG_MAX / a) {

            count++;

            cur = y;

            break;

        }

        cur = cur * a;

        count++;

    }

    if (cur >= y) {

        printf("%d\n", count);

    } else {

        printf("-1\n");

    }

    free(arr);

    return 0;

}

十一、跳台阶

  青蛙跳台阶问题,一只青蛙可以跳上1级或者2级台阶。求跳上n级台阶的不同跳法总数。

#include <stdio.h>

int main() {

    int n;

    scanf("%d", &n);

    if (n <= 1) {

        printf("1\n");

        return 0;

    }

    int a = 1;  // f(0)

    int b = 1;  // f(1)

    int c;

    for (int i = 2; i <= n; i++) {

        c = a + b;

        a = b;

        b = c;

    }

    printf("%d\n", c);

    return 0;

}

十二、吃糖果,求最多能吃的糖果数量

#include <stdio.h>

#include <stdlib.h>

int compare(const void *a, const void *b) {

    long long num1 = *(const long long *)a;

    long long num2 = *(const long long *)b;

    if (num1 < num2) return -1;

    if (num1 > num2) return 1;

    return 0;

}

int main() {

    int n;

    long long k;

    scanf("%d %lld", &n, &k);

    long long *a = (long long *)malloc(n * sizeof(long long));

    for (int i = 0; i < n; i++) {

        scanf("%lld", &a[i]);

    }

    qsort(a, n, sizeof(long long), compare);

    long long sum = 0;

    int count = 0;

    for (int i = 0; i < n; i++) {

        if (sum + a[i] <= k) {

            sum += a[i];

            count++;

        } else {

            break;

        }

    }

    printf("%d\n", count);

    free(a);

    return 0;

}

十三、开心还是难过(输出Happy,Just so so, Sad)

#include <stdio.h>

#include <string.h>

int main() {

    char str[105];

    fgets(str, sizeof(str), stdin);

    int len = strlen(str);

    if (len > 0 && str[len-1] == '\n') {

        str[len-1] = '\0';

        len--;

    }

    if (len < 3) {

        printf("None\n");

        return 0;

    }

    int happy_count = 0;

    int sad_count = 0;

    for (int i = 0; i <= len - 3; i++) {

        if (str[i] == ':' && str[i+1] == '-') {

            if (str[i+2] == ')') {

                happy_count++;

            } else if (str[i+2] == '(') {

                sad_count++;

            }

        }

    }

    if (happy_count == 0 && sad_count == 0) {

        printf("None\n");

    } else if (happy_count > sad_count) {

        printf("Happy\n");

    } else if (happy_count == sad_count) {

        printf("Just so so\n");

    } else {

        printf("Sad\n");

    }

    return 0;

}

十四、dd爱科学1.0(大科学家研究转基因白菜)

 

#include <stdio.h>

#include <string.h>

int main() {

    int n;

    scanf("%d", &n);

    char s[n + 1];

    scanf("%s", s);

    int dp[26] = {0};          // dp[c]:以字符 c 结尾的最长非递减子序列长度

    int prefix[26] = {0};      // prefix[c]:字符 0 到 c 的 dp 最大值

    for (int i = 0; i < n; i++) {

        int c = s[i] - 'A';    // 将字符转换为 0-25 的整数

        int new_len = prefix[c] + 1;   

        if (new_len > dp[c]) {

            dp[c] = new_len;

            if (new_len > prefix[c]) {

                prefix[c] = new_len;

                for (int j = c + 1; j < 26; j++) {

                    if (prefix[j] < new_len) {

                        prefix[j] = new_len;

                    } else {

                        break;                    }

                }

            }

        }

    }

    printf("%d\n", n - prefix[25]);

    return 0;

}

十五、对称之美(给定t组测试数据,每组包含n个字符串,要求每个字符串中恰好选择一个字符(新字符串的第I个字符来自第i个字符串),判断是否能够组成一个回文字符串)

#include <stdio.h>

#include <string.h>

int main() {

    int t;

    scanf("%d", &t);

    while (t--) {

        int n;

        scanf("%d", &n);

        char s[100][55];  

        for (int i = 0; i < n; i++) {

            scanf("%s", s[i]);

        }

        int left = 0, right = n - 1;

        int flag = 1;  

        while (left < right) {

            int charSet = 0;  

            for (int i = 0; s[left][i]; i++) {

                charSet |= (1 << (s[left][i] - 'a'));

            }

            int found = 0;  

            for (int i = 0; s[right][i]; i++) {

                if (charSet & (1 << (s[right][i] - 'a'))) {

                    found = 1;

                    break;

                }

            }

            if (!found) {

                flag = 0;  

                break;

            }

            left++;

            right--;

        }

        printf("%s\n", flag ? "Yes" : "No");

    }

    return 0;

}

十六、数字游戏(给定一个非负整数x,如果x的二进制表示中,1的个数为奇数,则将最低位取反。如果x的二进制表示中1的个数是偶数,则将最高位的1取反,求输出的操作数)

#include <stdio.h>

static inline int read() {

    int x = 0;

    char c = getchar();

    while (c < '0' || c > '9')

        c = getchar();

    while (c >= '0' && c <= '9') {

        x = x * 10 + (c - '0');

        c = getchar();

    }

    return x;

}

int main() {

    int t = read();  // 读取测试组数

    while (t--) {

        unsigned int x = read();  // 读取当前整数

        if (x == 0) {

            printf("0\n");  // x=0时直接输出0

            continue;

        }

        int cnt = 0;  // 操作次数计数器

        while (x) {

            if (__builtin_popcount(x) % 2) {

                x ^= 1;  // 翻转最低位

            } else {

                // 计算最高位位置并翻转

                int h = 31 - __builtin_clz(x);

                x ^= (1U << h);

            }

            cnt++;  // 操作计数

        }

        printf("%d\n", cnt);

    }

    return 0;

}

十七、牛牛的Ackmann(计算阿克曼函数的值)

#include <stdio.h>

long long ackmann(long long m, long long n) {

    if (m == 0) {

        return n + 1;

    } else if (n == 0) {

        return ackmann(m - 1, 1);

    } else {

        return ackmann(m - 1, ackmann(m, n - 1));

    }

}

int main() {

    long long n, m;

    // 输入顺序:第一个数是n,第二个数是m

    scanf("%lld %lld", &n, &m);

    // 计算A(m, n)并输出结果

    printf("%lld\n", ackmann(m, n));

    return 0;

}

十八、游游的字母串(游游有一个仅包含小写字母的字符串,她可以通过操作将任意字母变成与其相邻的字母,相邻规则为环形:ab相邻,zy相邻,az也相邻),每次操作代价为1

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#define min(a, b) ((a) < (b) ? (a) : (b))

int main() {

    char s[100001];

    scanf("%s", s);

    int n = strlen(s);

    // 统计每个字母出现的次数

    int cnt[26] = {0};

    for (int i = 0; i < n; i++) {

        cnt[s[i] - 'a']++;

    }

    // 初始化最小操作次数为极大值

    long long min_ops = 1e18;

    // 枚举目标字母(0-25 对应 'a'-'z')

    for (int target = 0; target < 26; target++) {

        long long total_ops = 0;

        // 计算当前目标字母的总操作次数

        for (int c = 0; c < 26; c++) {

            if (cnt[c] == 0) continue;

            int diff = abs(c - target);

            int ops = min(diff, 26 - diff);

            total_ops += (long long)ops * cnt[c];

        }

        // 更新最小操作次数

        if (total_ops < min_ops) {

            min_ops = total_ops;

        }

    }

    printf("%lld\n", min_ops);

    return 0;

}

十九、树上最短路(完全二叉树,询问节点编号ab,要求计算它们之间的最短路径长度)

#include <stdio.h>

int main() {

    int T;

    scanf("%d", &T);

    while (T--) {

        long long a, b;  // 使用long long确保大整数处理

        scanf("%lld %lld", &a, &b);

        int steps = 0;

        while (a != b) {

            if (a > b) {

                a = a / 2;  // 较大节点向上移动

            } else {

                b = b / 2;

            }

            steps++;  // 每次移动距离加1

        }

        printf("%d\n", steps);

    }

    return 0;

}

二十、二叉树(给定两个正整数nm,计算节点个数为n且树的高度不超过m的不同二叉树的方案数,结果需要度109次方+7取模)

#include <stdio.h>

#define MOD 1000000007

int main() {

    int n, m;

    scanf("%d %d", &n, &m);

    // dp[i][j]: i个节点组成高度不超过j的二叉树方案数

    long long dp[51][51] = {0};

    // 初始化:空树方案数为1

    for (int j = 0; j <= m; j++) {

        dp[0][j] = 1;

    }

    // 动态规划递推

    for (int i = 1; i <= n; i++) {

        for (int j = 1; j <= m; j++) {

            dp[i][j] = 0;

            // 分配i-1个节点给左右子树

            for (int k = 0; k < i; k++) {

                dp[i][j] = (dp[i][j] + dp[k][j-1] * dp[i-1-k][j-1]) % MOD;

            }

        }

    }

    printf("%lld\n", dp[n][m]);

    return 0;

}

二十一、小红的子序列逆序对

#include <stdio.h>

#include <stdlib.h>

#define MOD 1000000007

// 快速幂计算 base^exp % mod

long long quick_pow(long long base, long long exp, long long mod) {

    long long res = 1;

    base %= mod;

    while (exp) {

        if (exp & 1) {

            res = (res * base) % mod;

        }

        base = (base * base) % mod;

        exp >>= 1;

    }

    return res;

}

// 归并排序求逆序对

long long merge(int arr[], int left, int mid, int right) {

    int i = left, j = mid + 1, k = 0;

    long long cnt = 0;

    int *temp = (int *)malloc((right - left + 1) * sizeof(int));

    while (i <= mid && j <= right) {

        if (arr[i] <= arr[j]) {

            temp[k++] = arr[i++];

        } else {

            cnt += (mid - i + 1); // 左半部分剩余元素均大于 arr[j]

            temp[k++] = arr[j++];

        }

    }

    while (i <= mid) temp[k++] = arr[i++];

    while (j <= right) temp[k++] = arr[j++];

    for (i = left, k = 0; i <= right; i++, k++) {

        arr[i] = temp[k];

    }

    free(temp);

    return cnt;

}

long long merge_sort(int arr[], int left, int right) {

    if (left >= right) return 0;

    int mid = (left + right) / 2;

    long long cnt = merge_sort(arr, left, mid);

    cnt += merge_sort(arr, mid + 1, right);

    cnt += merge(arr, left, mid, right);

    return cnt;

}

int main() {

    int n;

    scanf("%d", &n);

    int *a = (int *)malloc(n * sizeof(int));

    for (int i = 0; i < n; i++) {

        scanf("%d", &a[i]);

    }

    if (n < 2) {

        printf("0\n");

        free(a);

        return 0;

    }

    // 计算逆序对总数

    long long cnt = merge_sort(a, 0, n - 1);

    // 计算 2^(n-2) mod MOD

    long long base = quick_pow(2, n - 2, MOD);

    // 结果取模

    long long ans = (cnt % MOD) * (base % MOD) % MOD;

    printf("%lld\n", ans);   

    free(a);

    return 0;

}

二十二、小美和大富翁(《大富翁》游戏,求金币数量)

#include <stdio.h>

#include <string.h>

#define MAX_N 100000

#define MASK_CNT 16

#define INF (1LL << 60)

long long dp[MAX_N + 1][MASK_CNT];

int a[MAX_N + 1];

int main() {

    int n;

    scanf("%d", &n);

    for (int i = 1; i <= n; i++) {

        scanf("%d", &a[i]);

    }

    // 初始化 dp 数组为负无穷

    for (int i = 0; i <= n; i++) {

        for (int mask = 0; mask < MASK_CNT; mask++) {

            dp[i][mask] = -INF;

        }

    }

    dp[0][0] = 0;

    for (int i = 0; i <= n; i++) {

        if (dp[i][15] > dp[i][0]) {

            dp[i][0] = dp[i][15];

        }

        for (int mask = 0; mask < MASK_CNT; mask++) {

            if (dp[i][mask] <= -INF) continue;  // 跳过无效状态

            for (int d = 1; d <= 4; d++) {

                if (mask & (1 << (d - 1))) continue;  // 已使用过该卡牌

                int j = i + d;  // 目标城市

                if (j > n) continue;  // 超出城市范围

                int new_mask = mask | (1 << (d - 1));  // 新卡牌集合

                long long new_val = dp[i][mask] + a[j];  // 新金币值

                // 若金币非负且更优,则更新状态

                if (new_val >= 0 && new_val > dp[j][new_mask]) {

                    dp[j][new_mask] = new_val;

                }

            }

        }

    }

    long long ans = -INF;

    for (int mask = 0; mask < MASK_CNT; mask++) {

        if (dp[n][mask] > ans) ans = dp[n][mask];

    }

    if (ans < 0) {

        printf("-1\n");

    } else {

        printf("%lld\n", ans);

    }

    return 0;

}

二十三、小美的数组删除(小美有一个长度为n的数组a,她可以进行两种操作:1、删除数组的第一个元素,花费为c,数组长度-1 2xx)

#include <stdio.h>

#include <string.h>

#define MAX_N 200010

int a[MAX_N];

int freq[MAX_N];

long long mex_suffix[MAX_N];

int main() {

    int T;

    scanf("%d", &T);

    while (T--) {

        int n;

        long long k, c;

        scanf("%d %lld %lld", &n, &k, &c);

        for (int i = 1; i <= n; i++) {

            scanf("%d", &a[i]);

        }

        // 清空频率数组(0 n+1

        for (int i = 0; i <= n + 1; i++) {

            freq[i] = 0;

        }

        mex_suffix[n + 1] = 0;  // 空后缀的 MEX 0

        int mex = 0;

        // 从后往前计算后缀 MEX

        for (int i = n; i >= 1; i--) {

            int x = a[i];

            if (x <= n) {

                freq[x]++;

            }

            // 更新 MEX:找到第一个未出现的非负整数

            while (mex <= n + 1 && freq[mex] > 0) {

                mex++;

            }

            mex_suffix[i] = mex;

        }

        // 枚举分割点 i,计算最小花费

        long long ans = (long long)n * c;  // 初始化为只使用操作1的花费

        for (int i = 0; i <= n; i++) {

            long long cost = (long long)i * c + k * mex_suffix[i + 1];

            if (cost < ans) {

                ans = cost;

            }

        }

        printf("%lld\n", ans);

    }

    return 0;

}

二十四、小红的爆炸串(定义一个字符串会爆炸,k=2时,arc会爆炸,aabb不会爆炸)

#include <stdio.h>

#include <string.h>

#define maxn 200010

#define maxn2 400020

int n, k;

char s[maxn];

int sum[maxn];

int tree[maxn2];

int lowbit(int x) {

    return x & -x;

}

void update(int idx, int val) {

    while (idx < maxn2) {

        tree[idx] += val;

        idx += lowbit(idx);

    }

}

int query(int idx) {

    int res = 0;

    if (idx <= 0) return 0;

    while (idx) {

        res += tree[idx];

        idx -= lowbit(idx);

    }

    return res;

}

int main() {

    scanf("%d %d", &n, &k);

    scanf("%s", s);

    sum[0] = 0;

    for (int i = 1; i < n; i++) {

        sum[i] = sum[i-1] + (s[i] != s[i-1] ? 1 : 0);

    }

    memset(tree, 0, sizeof(tree));

    long long ans = 0;

    int offset = n + 5;  // 偏移量处理负值

    for (int r = 0; r < n; r++) {

        update(sum[r] + offset, 1);

        int target = sum[r] - k;

        int cnt;

        if (target + offset < 1) {

            cnt = 0;

        } else {

            cnt = query(target + offset);

        }

        ans += (r + 1) - cnt;  // 满足条件的子串数

    }

    printf("%lld\n", ans);

    return 0;

}

二十五、小美()的数位操作(可以对n的每一位进行至多一次操作(+1或者-1)),但有以下限制:9不能进行加1操作,0不能进行减1操作

#include <stdio.h>

#include <string.h>

#include <stdlib.h>

int main() {

    long long n, p;

    scanf("%lld %lld", &n, &p);

    char str[20];

    sprintf(str, "%lld", n);

    int len = strlen(str);

    int digits[20];

    for (int i = 0; i < len; i++) {

        digits[i] = str[i] - '0';

    }

    long long pow3[20];

    pow3[0] = 1;

    for (int i = 1; i <= len; i++) {

        pow3[i] = pow3[i - 1] * 3;

    }

    long long total_states = pow3[len];

    for (long long s = 0; s < total_states; s++) {

        char new_str[20];

        long long current = 0;

        int valid = 1;

        for (int i = 0; i < len; i++) {

            int op = (s / pow3[i]) % 3;

            int d = digits[i];

            int new_digit;

            if (op == 0) {

                new_digit = d;

            } else if (op == 1) {

                if (d == 9) {

                    valid = 0;

                    break;

                }

                new_digit = d + 1;

            } else {

                if (d == 0) {

                    valid = 0;

                    break;

                }

                new_digit = d - 1;

            }

            new_str[i] = '0' + new_digit;

            current = (current * 10 + new_digit) % p;

        }

        if (!valid) continue;

        new_str[len] = '\0';

        if (current % p == 0) {

            printf("%s\n", new_str);

            return 0;

        }

    }

    printf("-1\n");

    return 0;

}

二十六、函数(定义一个十进制的正整数为”完美数”,要求每个n,输出最大的不超过n的完美数)

#include <stdio.h>

#include <string.h>

#define MAX_DIGITS 20

int main() {

    int T;

    scanf("%d", &T);

    while (T--) {

        char n_str[MAX_DIGITS];

        scanf("%s", n_str);

        int len = strlen(n_str);

        int cur[MAX_DIGITS] = {0};

        int res[MAX_DIGITS] = {0};

        for (int i = 0; i < len; i++) {

            cur[i] = 3;

        }

        int i = 0;

        while (i >= 0) {

            if (i == len) {

                break;

            }

            int digit = n_str[i] - '0';

            int found = 0;

            for (int d = cur[i]; d >= 1; d--) {

                if (d > 3) continue;

                if (d <= digit) {

                    res[i] = d;

                    if (d < digit) {

                        for (int j = i + 1; j < len; j++) {

                            res[j] = 3;

                        }

                        i = len;

                        found = 1;

                        break;

                    } else {

                        i++;

                        found = 1;

                        break;

                    }

                }

            }

            if (i == len) {

                break;

            }

            if (!found) {

                i--;

                if (i < 0) {

                    break;

                }

                cur[i]--;

                for (int j = i + 1; j < len; j++) {

                    cur[j] = 3;

                }

            }

        }

        if (i == len) {

            long long num = 0;

            for (int j = 0; j < len; j++) {

                num = num * 10 + res[j];

            }

            printf("%lld\n", num);

        } else {

            long long num = 0;

            for (int j = 0; j < len - 1; j++) {

                num = num * 10 + 3;

            }

            printf("%lld\n", num);

        }

    }

    return 0;

}

二十七、子序列(子序列定义: 从原字符串中删除0个或者多个字符而不改变剩余字符相对位置形成的新序列)

#include <stdio.h>

#include <string.h>

#define MOD 1000000007

#define MAX_LEN 100010

long long mod_exp(long long base, long long exp, long long mod) {

    long long res = 1;

    base %= mod;

    while (exp) {

        if (exp & 1) {

            res = (res * base) % mod;

        }

        base = (base * base) % mod;

        exp >>= 1;

    }

    return res;

}

int main() {

    int n, k;

    char s[MAX_LEN];

    scanf("%d %d", &n, &k);

    scanf("%s", s);

    int cnt[26] = {0};

    for (int i = 0; i < n; i++) {

        cnt[s[i] - 'a']++;

    }

    long long val[26];

    for (int i = 0; i < 26; i++) {

        if (cnt[i] > 0) {

            val[i] = mod_exp(2, cnt[i], MOD) - 1;

        } else {

            val[i] = 0;

        }

    }

    long long dp[27] = {0};

    dp[0] = 1; // 初始状态:空集合

    for (int i = 0; i < 26; i++) {

        // 从大到小更新 dp[j]

        for (int j = k; j >= 1; j--) {

            dp[j] = (dp[j] + dp[j - 1] * val[i]) % MOD;

        }

    }

    printf("%lld\n", dp[k]);

    return 0;

}

posted @ 2025-06-25 17:47  815034762  阅读(154)  评论(0)    收藏  举报