SWJTU OJ 西安交通大学第十三届ACM程序设计决赛-题解

来源:互联网 发布:现在做农村淘宝赚钱吗 编辑:程序博客网 时间:2024/03/28 19:26

A Knapsack Problem(线性时间复杂度 签到题)

#include <stdio.h>int main(){int T;scanf("%d", &T);while(T-- > 0) {int n, w, d, i, tmp;scanf("%d%d%d", &n, &w, &d);for (i= 0; i < n; ++i) {scanf("%d", &tmp);w -= tmp;}for (i = 0; i < n; ++i) {scanf("%d", &tmp);d -= tmp;}if (w >= 0 && d >= 0) {puts("YES");}else {puts("NO");}}return 0;} 

B Matrix  O(n * n + q)

(r[k] = v意为第k行被置为v;c[k] = v,意为k列被置为v,rt[k] = i 意为修改第k行的值的时间为“第i次操作”, ct[k] = i 意为修改第k列的时间为“第i次操作”, matrix[i][j]的值为最近对行列操作给的值

#include <cstdio>#include <iostream>#include <algorithm> #include <cstring>#include <string>#include <climits>#include <cmath>using namespace std;const int maxn = 5e2 + 7;int n, q;int matrix[maxn][maxn];int r[maxn], c[maxn], rt[maxn], ct[maxn];int main(){int T;scanf("%d", &T);while(T-- > 0) {scanf("%d%d", &n, &q);//memset(matrix, 0, sizeof(int)*maxn * maxn);memset(r, 0, sizeof(int) * maxn);memset(c, 0, sizeof(int) * maxn);memset(rt, 0, sizeof(int) * maxn);memset(ct, 0, sizeof(int) * maxn);for (int i = 1; i <= q; ++i) {int op, k, v;scanf("%d%d%d", &op, &k, &v);if (op == 1) {r[k] = v;rt[k] = i;//记录修改的时间 }else if (op == 2) {c[k] = v;ct[k] = i; }}for (int i = 1; i <= n; ++i) {for (int j = 1; j <= n; ++j) {if (rt[i] > ct[j]) { //它们是不可能相等的 matrix[i][j] = r[i]; }else {matrix[i][j] = c[j];}}}for (int i = 1; i <= n; ++i) {printf("%d", matrix[i][1]);for (int j = 2; j <= n; ++j){printf(" %d", matrix[i][j]);}puts("");}} return 0;} 


D Music Problem Music Problem O(n * mod)

DP,优化了一下空间(用两个一维向量代替了矩阵),用鸽巢原理做了一下简单的优化。

就是中一些数字,使它们的和sum可以被一个数mod整除。余数最多有mod个(0:mod - 1),求出所有的余数。有余数0就说明有解。

#include <stdio.h>#include <string.h>#define MOD 3600#define MAXN 100007int ary[MAXN];char est[MOD + 7], i_est[MOD +7];int main(){int T;scanf("%d", &T);while(T-- > 0) {memset(est, 0, sizeof(char) * (MOD + 7));memset(i_est, 0, sizeof(char) * (MOD + 7));int n, i, j;scanf("%d", &n);for (i= 0; i < n; ++i) {scanf("%d", ary + i);}if (n > 3600) {puts("YES");continue;//“组合数学”中的鸽巢原理 }else {for (i = 0; i < n; ++i) {for (j = 1; j < MOD; ++j) {if (est[j] == 1) {i_est[(j + ary[i]) % MOD] = 1;} }i_est[ary[i] % MOD] = 1;if (i_est[0] == 1) {est[0] = 1;break;}memcpy(est, i_est, sizeof(char) * (MOD + 7));}if (est[0]) {puts("YES");}else {puts("NO");}} }return 0;} 


F Maximize The Beatiful Value O(N)

由于序列非递减,所以第i个数向左刚好移动k步美丽值减少的最少。

先用pre数组保存a[]序列的前缀和。sum 为不移动时的美丽值。

将a[i] 移动到a[i - k - 1]时,a[i - k - 1], a[i -k], a[i - k + 1], ..., a[i - 1] 被向右挤了一个位置。美丽值增加了它们的和(即pre[i - 1] - pre[i - k - 1]),但减少了k 倍的a[i](因为a[i] 左移k位,权值由i变为了i - k)。

总的来说:美丽值增加了 pre[i - 1] - pre[i - k - 1] - a[i] * k(为负值,想一想,为什么?)

#include <cstdio>#include <algorithm> #include <climits> using namespace std;const int maxn = 1e5 + 7;long long ary[maxn], pre[maxn];int main(){int T;scanf("%d", &T);while(T--) {int n, k;long long sum = 0;scanf("%d%d", &n, &k);pre[0] = 0;for (int i= 1; i <= n; ++i) {scanf("%d", ary + i);pre[i] = pre[i - 1] + ary[i];sum += ary[i] * i;} //得到初始的魅力值 long long minV = LLONG_MAX; //减少的最小值 for (int i = k + 1; i <= n; ++i) {minV = min(minV, -(pre[i - 1] - pre[i - k - 1] - ary[i] * k));}printf("%lld\n", sum - minV); }return 0;} 


K Segment Tree  O(n)

前缀和presum[i]保存1到i出现的次数,线性时间复杂度,不用暴力就可以

#include <stdio.h>#include <string.h>const int maxn = 1e2 + 7;int ary[maxn];int presum[maxn];int main(){int T;scanf("%d", &T);while(T-- > 0 ) {int n, k, d, tmp, cnt = 0;memset(ary, 0, sizeof(int) * maxn);scanf("%d%d%d", &n, &k, &d);for (int i= 1; i <= n; ++i) {scanf("%d", &tmp);ary[tmp]++;}presum[0] = 0;for (int i = 1; i <= n; ++i) {presum[i] = presum[i - 1] + ary[i];} //前缀和,保存(1:i)出现次数 int End = n - d + 1;for (int i = 1; i <= End; ++i) {int R = i+ k - 1; if (R > n) {R = n;}if (presum[R] - presum[i - 1] >= d) {cnt++;}}printf("%d\n", cnt);}return 0;} 




=========未完待续=======


by wjsay






阅读全文
0 0
原创粉丝点击