牛客网编程题
一、小红的字符串(给定由’1’到’9’组成的数字串(不含’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’组成,她可以进行任意次操作,每次操作选择一个字符将其取反(0变1,1变0),求将给定字符串变成好串的最小操作次数】)
#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个站点,编号从1到n,如果选择顺时针/逆时针行走,计算两个方向的最短的距离)
#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的排列,包含1到n每个整数恰好一次的数组,判断两个指定的整数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;
}
十八、游游的字母串(游游有一个仅包含小写字母的字符串,她可以通过操作将任意字母变成与其相邻的字母,相邻规则为环形:’a’与’b’相邻,’z’与’y’相邻,且’a’与’z’也相邻),每次操作代价为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;
}
十九、树上最短路(完全二叉树,询问节点编号a和b,要求计算它们之间的最短路径长度)
#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;
}
二十、二叉树(给定两个正整数n和m,计算节点个数为n且树的高度不超过m的不同二叉树的方案数,结果需要度10的9次方+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 2、xx)
#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;
}

浙公网安备 33010602011771号