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 100007
int 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
\
\
\
\