先计算出所有子串是否是回文串,这个步骤的时间复杂度应该是O(N*N),然后再进行动态规划,当前的最少切割是有前面的最少切割所推导出来的,总的最坏时间复杂度是O(N *N)。
#include
#include
#define MAXN 1000
#define MIN(a, b) (a < b ? a : b)
int sub[MAXN][MAXN];
void preprocess(char str[], int len) {
int a, b, l, r;
for (a = 0; a < MAXN; ++a) {
for (b = 0; b < MAXN; ++b) {
sub[a][b] = 0;
}
}
for (a = 0; a < len; ++a) {
l = a, r = a;
while (0 <= l && r < len && str[l] == str[r]) {
sub[l][r] = 1;
l -= 1, r += 1;
}
l = a, r = a + 1;
while (0 <= l && r < len && str[l] == str[r]) {
sub[l][r] = 1;
l -= 1, r += 1;
}
}
}
int main() {
int T, dp[1000], len, a, b, c;
char str[1001];
scanf("%d", &T);
while (T--) {
scanf("%s", str);
len = strlen(str);
preprocess(str, len);
//for (a = 0; a < MAXN; ++a) dp[a] = 0;
dp[0] = 1;
for (a = 1; a < len; ++a) {
dp[a] = dp[a - 1] + 1;
for (b = a - 1; b >= 0; --b) {
if (sub[b][a]) {
if (b == 0) dp[a] = 1;
else dp[a] = MIN(dp[a], dp[b - 1] + 1);
}
}
}
printf("%d\n", dp[len - 1] - 1);
}
return 0;
}
每个按钮最多按一次,所以当前按钮的按或不按,只取决于当前按钮的状态和前一个按钮的状态,以此来进行下一步搜索,边缘情况特殊处理即可。可能我的状态表示方法略有欠妥,可自行斟酌。
#include
#include
#define INF 30
#define MIN(a, b) (a < b ? a : b)
char str[30], check[30];
void change(int pos, int len) {
if (pos == 0) {
if (str[pos] == '1') str[pos] = '0';
else str[pos] = '1';
if (pos + 1 == len) return;
if (str[pos + 1] == '1') str[pos + 1] = '0';
else str[pos + 1] = '1';
return;
}
if (str[pos - 1] == '1') str[pos - 1] = '0';
else str[pos - 1] = '1';
if (str[pos] == '1') str[pos] = '0';
else str[pos] = '1';
if (pos + 1 == len) return;
if (str[pos + 1] == '1') str[pos + 1] = '0';
else str[pos + 1] = '1';
return;
}
int solve(int pos, int len, int step) {
int res = INF, tmp;
if (pos == len) {
return str[pos - 1] == check[pos - 1] ? step : INF;
}
if (pos == 0) {
tmp = solve(pos + 1, len, step);
res = MIN(res, tmp);
change(pos, len);
tmp = solve(pos + 1, len, step + 1);
res = MIN(res, tmp);
change(pos, len);
return res;
}
if (str[pos - 1] == check[pos - 1]) {
tmp = solve(pos + 1, len, step);
res = MIN(res, tmp);
} else {
change(pos, len);
tmp = solve(pos + 1, len, step + 1);
res = MIN(res, tmp);
change(pos, len);
}
return res;
}
int main() {
int res = INF, len;
while (scanf("%s%s", str, check) != EOF) {
len = strlen(str);
if (len != strlen(check)) printf("impossible\n");
res = solve(0, len, 0);
if (res == INF) printf("impossible\n");
else printf("%d\n", res);
}
return 0;
}
目前有一个最坏时间复杂度为O(N*logN *logN)的思路,代码没有敲完,有兴趣讨论的朋友可以私信我。
先全部大写转小写,然后逐一去掉空格。
#include
#include
void to_lowercase(char *str) {
int a, len = strlen(str);
for (a = 0; a < len; ++a) {
if (str[a] < 97 && str[a] != ' ') str[a] += 32;
}
}
void remove_space(char *str) {
int a, b = 0, len = strlen(str);
for (a = 0; a < len; ++a) {
if (str[a] != ' ') str[b++] = str[a];
}
for (a = b; a < len; ++a) str[a] = 0;
}
int main() {
char stra[10000], strb[10000];
int a, lena, lenb, res = 1;
gets(stra), gets(strb);
to_lowercase(stra), to_lowercase(strb);
remove_space(stra), remove_space(strb);
lena = strlen(stra), lenb = strlen(strb);
if (lena != lenb) res = 0;
//printf("%s\n%s\n", stra, strb);
for (a = 0; a < (lena & lenb); ++a) {
if (stra[a] != strb[a]) res = 0;
}
printf("%s\n", (res ? "YES" : "NO"));
return 0;
}
先排序,再判断所有区间是否能连接起来。
但是介于数据范围,也可以用哈希解决此题。O(N * N)的最坏时间复杂度理论上是过不了的,但是最后确实有人这样做,然后拿到了Accepted,这就不科学了。
#include
typedef struct pair {
int l, r;
}pair;
int compare(const void *a, const void *b) {
return ((pair *)a)->l - ((pair *)b)->l;
}
int main() {
int a, b, l, r, ok = 1, N;
pair region[50000];
scanf("%d", &N);
for (a = 0; a < N; ++a) {
scanf("%d%d", ®ion[a].l, ®ion[a].r);
}
qsort(region, N, sizeof(pair), compare);
l = region[0].l;
r = region[0].r;
for (a = 1; a < N; ++a) {
if (r < region[a].l) {
ok = 0;
break;
}
r = r < region[a].r ? region[a].r : r;
}
if (ok) printf("%d %d\n", l, r);
else printf("no\n");
return 0;
}
这道题的重点在于环,本来应该是一道简单题目的,可能大多数同学都缺少这类型题目的处理经验吧。介于这题的数据范围很小,解决这道题目,只需将将每个串加倍,然后暴力去找到最长的公共子串即可。
#include
#include
#define MAX(a, b) a > b ? a : b
int main() {
char stra[10000], strb[10000];
int a, b, tmp, res = 0, lena, lenb;
scanf("%s%s", stra, strb);
lena = strlen(stra), lenb = strlen(strb);
for (a = 0; a < lena; ++a) stra[a + lena] = stra[a];
for (a = 0; a < lenb; ++a) strb[a + lenb] = strb[a];
stra[lena * 2] = 0, strb[lenb * 2] = 0;
//printf("%s\n%s\n", stra, strb);
for (a = 0; a < lena * 2; ++a) {
for (b = 0; b < lenb * 2; ++b) {
tmp = 0;
while (tmp + a < lena * 2 &&
tmp + b < lenb * 2 &&
stra[tmp + a] == strb[tmp + b] &&
tmp < lena && tmp < lenb) tmp += 1;
res = MAX(res, tmp);
}
}
printf("%d\n", res);
return 0;
}
这场比赛,没有接触过程序设计竞赛的同学来讲,还是有很多道签到题,这题就是其中一道。
#include
int main() {
double N, fN;
scanf("%lf", &N);
if (0 <= N && N < 5) fN = -N + 2.5;
else if (5 <= N && N < 10) fN = 2 - 1.5 * (N - 3) * (N - 3);
else if (10 <= N && N < 20) fN = N * 1.0 / 2 - 1.5;
printf("%.3lf\n", fN);
return 0;
}
一个不足十位的数,没有0,删去K位。直接枚举出所有可能的数,找到一个最小的。枚举出所有的可能的数最多也就C(10,5)个,所以,应该只是考察代码能力吧。
#include
#include
#define MIN(a, b) (a < b ? a : b)
#define INF 1e9
int solve(char *number, int len, int n, int K) {
int a, b;
for (a = 0; a < len; ++a) {
if (n >> a & 1) continue;
K -= 1;
}
if (K) return INF;
for (a = 0, b = 0; a < len; ++a) {
if (n >> a & 1) {
b = b * 10 + (number[a] - '0');
}
}
return b;
}
int main() {
int T, K, len, res, a, b;
char number[10];
scanf("%d", &T);
while (T--) {
scanf("%s%d", number, &K);
len = strlen(number);
res = INF;
for (a = 0; a < 1 << len; ++a) {
b = solve(number, len, a, K);
res = MIN(res, b);
}
printf("%d\n", res);
}
return 0;
}
签到题。
#include
int main() {
int N, x, ok;
double t;
char flag[5];
scanf("%d", &N);
while (N--) {
scanf("%lf%d%s", &t, &x, flag);
ok = 1;
if (t < 7.0 || t > 8.0) ok = 0;
if (x < 1500) ok = 0;
if (flag[0] == 'N' && flag[1] == 'o') ok = 0;
//printf("flag: %s\n", flag);
printf(ok ? "Yes\n" : "No\n");
}
return 0;
}
签到题。
#include
void swap(int *a, int *b) {
int t = *a;
*a = *b;
*b = t;
}
int main() {
int a, b, c;
scanf("%d%d%d", &a, &b, &c);
if (a < b) swap(&a, &b);
if (a < c) swap(&a, &c);
if (b < c) swap(&b, &c);
printf("%d %d %d\n", a, b, c);
return 0;
}
先排序,然后两个循环枚举两个不同的数,再通过二分查找去判断集合中是否存在这个两个数的乘积,O(N *N *logN)的最坏时间复杂度就能拿到Accepted。注意爆int,注意去重。
#include
#define ll long long
int compare(const void *a, const void *b) {
return (int)((*(ll *)a) - (*(ll *)b));
}
int find(ll *arr, int len, ll val) {
int l = 0, r = len, mid;
while (l < r) {
mid = l + (r - l) / 2;
if (val == arr[mid]) return 1;
if (val < arr[mid]) r = mid;
else l = mid + 1;
}
return val == arr[l];
}
int main() {
int N, res = 0;
ll arr[1000];
int a, b, c;
scanf("%d", &N);
for (a = 0; a < N; ++a) scanf("%lld", arr + a);
qsort(arr, N, sizeof(arr[0]), compare);
for (a = 0; a < N; ++a) {
for (b = a + 1; b < N; ++b) {
if (arr[a] != 1 && find(arr, N, arr[a] * arr[b])) {
res += 1;
}
}
}
printf("%d\n", res);
return 0;
}
这题有很多种不同的解法,主要在于自己怎么推导公式。
#include
#define ll long long
int main() {
int N, M;
ll arr[21], a;
for (arr[0] = arr[1] = 1, a = 2; a <= 20; ++a) {
arr[a] = arr[a - 1] * a;
}
while (scanf("%d%d", &N, &M) != EOF) {
if (N < M) {
printf("0\n");
continue;
}
printf("%lld\n", arr[N] / arr[N - M] / arr[M]);
}
return 0;
}
知道有的同学肯定会先筛选素数,但是如果仔细想想,确实是没有必要啊。
#include
int main() {
int N, a;
scanf("%d", &N);
printf("%d=", N);
for (a = 2; a <= N; ++a) {
while (N % a == 0) {
printf("%d", a);
if ((N /= a) != 1) printf("*");
}
}
printf("\n");
return 0;
}