T1
期望100-实际100
老师说是结论题。
其实可以直接打表,t[i]表示0-63中有t[i]对数与起来等于i,然后乘法原理即可。
(没什么难度。
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 100005;
const int mod = 1e9 + 7;
char s[MAXN];
int a[MAXN], t[64];
int main() {
scanf ("%s", s + 1);
int n = strlen(s + 1);
for(int i = 1; i <= n; i++) {
if('0' <= s[i] && s[i] <= '9')
a[i] = s[i] - '0';
else if('A' <= s[i] && s[i] <= 'Z')
a[i] = 10 + (s[i] - 'A');
else if('a' <= s[i] && s[i] <= 'z')
a[i] = 36 + (s[i] - 'a');
else if(s[i] == '-')
a[i] = 62;
else if(s[i] == '_')
a[i] = 63;
}
// for(int i = 1; i <= n; i++)
// printf("%d ", a[i]);
t[0] = 729; t[1] = 243; t[2] = 243; t[3] = 81; t[4] = 243; t[5] = 81; t[6] = 81; t[7] = 27; t[8] = 243; t[9] = 81; t[10] = 81; t[11] = 27; t[12] = 81; t[13] = 27; t[14] = 27; t[15] = 9; t[16] = 243; t[17] = 81; t[18] = 81; t[19] = 27; t[20] = 81; t[21] = 27; t[22] = 27; t[23] = 9; t[24] = 81; t[25] = 27; t[26] = 27; t[27] = 9; t[28] = 27; t[29] = 9; t[30] = 9; t[31] = 3; t[32] = 243; t[33] = 81; t[34] = 81; t[35] = 27; t[36] = 81; t[37] = 27; t[38] = 27; t[39] = 9; t[40] = 81; t[41] = 27; t[42] = 27; t[43] = 9; t[44] = 27; t[45] = 9; t[46] = 9; t[47] = 3; t[48] = 81; t[49] = 27; t[50] = 27; t[51] = 9;t[52] = 27; t[53] = 9; t[54] = 9; t[55] = 3; t[56] = 27; t[57] = 9; t[58] = 9; t[59] = 3; t[60] = 9; t[61] = 3; t[62] = 3; t[63] = 1;
long long ans = 1;
for(int i = 1; i <= n; i++) {
ans *= t[a[i]];
ans %= mod;
}
printf("%lld
", ans % mod);
return 0;
}
打表代码:
#include <cstdio>
int t[64];
int main() {
for(int i = 0; i <= 63; i++)
for(int j = 0; j <= 63; j++) {
int k = (i & j);
printf("%d = %d & %d
", k, i, j);
t[k]++;
}
for(int i = 0; i <= 63; i++)
printf("t[%d] = %d;
", i, t[i]);
return 0;
}
T2
期望100-实际9
老师说是最短路。
其实可以BFS-DFS,不过需要记忆化提速。每次在BFS里存储下一个点的坐标、到下一个点是上一次休息后过的第几条街、从起点到下一个点的距离。
可以在这里执行最优解剪枝。
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 105;
int dx[4] = { 0, 1, 0, -1 };
int dy[4] = { 1, 0, -1, 0 };
int map[MAXN][MAXN], n, T;
void read(int &a) {
a = 0;
int k = 1;
char s = getchar();
while (s < '0' || s > '9') {
if (s == '-')
k = -1;
s = getchar();
}
while (s >= '0' && s <= '9') {
a = (a << 3) + (a << 1) + s - '0';
s = getchar();
}
a *= k;
return;
}
struct node {
int x, y, step, dis;
node(int X, int Y, int S, int D) {
x = X;
y = Y;
step = S;
dis = D;
}
};
int ans[3][MAXN][MAXN];
void bfs(int sx, int sy) {
memset(ans, 0x3f, sizeof ans);
queue<node> q;
ans[0][sx][sy] = 0;
q.push(node(sx, sy, 0, 0));
while (!q.empty()) {
node t = q.front();
q.pop();
int x = t.x, y = t.y, di = t.dis, va = t.step;
if (ans[va][x][y] < t.dis) // 剪枝 1(如果走过的总路径都比之前存的答案长了,直接判断不是最优解
for(int i = 0; i < 4; i++) {
continue;
for (int i = 0; i < 4; i++) {
int cx = x + dx[i];
int cy = y + dy[i];
int val = va + 1;
int dis = di + T;
if (val == 3) {
val = 0;
dis += map[cx][cy];
}
if (cx < 1 || cx > n)
continue;
if (cy < 1 || cy > n)
continue;
if (ans[val][cx][cy] <= dis) // 剪枝 2(同剪枝 1
continue;
ans[val][cx][cy] = dis;
q.push(node(cx, cy, val, dis));
}
}
return;
}
int main() {
read(n);
read(T);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) read(map[i][j]);
bfs(1, 1);
printf("%d
", min(ans[1][n][n], min(ans[0][n][n], ans[2][n][n])));
return 0;
}
T3
期望100-实际77
一道完全背包,我记得我们之前做过类似题目的。
可以把这道题改写一下。对于第i天,第j件物品的价值就是它下一天的价格,第j件物品的重量就是它当天的价格,而背包容量就是上一天获得的最大价值。
所以做k-1次完全背包即可。
但有一个细节需要考虑:每一次背包不一定装满,而未装满的部分还能拿到下一次去用,所以每次跑完完全背包后,还要再遍历一遍。
#include <cstdio>
typedef long long LL;
const int MAXN = 55;
const int MAXD = 15;
const int MAXM = 1000005;
int v[MAXN][MAXD];
LL dp[MAXM], add[MAXM];
int Max(int x, int y) { return x > y ? x : y; }
int main() {
int n, d, m;
scanf("%d %d %d", &n, &d, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= d; j++) scanf("%d", &v[i][j]);
LL t = m;
for (int k = 2; k <= d; k++) {
for (int i = 1; i <= t; i++)
dp[i] = 0;
for (int i = 1; i <= n; i++)
for (int j = v[i][k - 1]; j <= t; j++)
if (dp[j] < dp[j - v[i][k - 1]] + v[i][k])
dp[j] = dp[j - v[i][k - 1]] + v[i][k];
int ma = 0;
for (int i = 0; i <= t; i++) ma = Max(ma, dp[i] + t - i);
// dp[i] 表示背包容量为 i 的最大价值,再加上 t - i 也就是没装完的部分
t = Max(ma, t);
}
printf("%lld
", t);
return 0;
}
T4
期望0-实际30????
当我们求到前缀和之后,就需要把所有的满足条件的超级音符选出最大的k个超级音符来。
又很显然,暴力排序跑是不可能的,因此,我们就需要换个方法。因为对于一个确定的起点i而言,找到以i为起点,往后数[l,r]这个区间的子段的最大值,是可求的。因为我们已经计算出来了前缀和,那么,[l,r]这个范围内的最大值减去i-1这个位置的前缀和就是我当前这个段能取得的最大值。
那么,对于我的答案而言,每次都选取这样的最优值,最后得到的是不是就是最优解?因此,我们可以用一个堆来存储这样的一些数据,存储对于每一个起点i而言,取出[i+l,i+r]这个范围内的最大值存入我们的优先队列。
当我们取走一个当前的局部最优解之后,又由于我这个区间范围内的次优解还可能比其他地方的最优解优,因此,假设t就是我们得到最优解得位置,我们在取走它之后,还需要再放进从i开始,[i+l,i+t-1]的最优解以及[i+t+1,i+r]的最优解,当然,如果t=l或者t=r时,需要特判。(思路来自LHY
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 500005;
long long a[MAXN], sum[MAXN];
long long n, m, L, R;
struct RMQ {
int v, index;
} st[MAXN][25];
struct data {
int l, r, l_, r_, t;
friend bool operator<(data x, data y) { return sum[x.r_] - x.t < sum[y.r_] - y.t; }
};
priority_queue<data> q;
void RMQ() {
for (int j = 1; (1 << j) <= n; j++)
for (int i = 0; i + (1 << j) - 1 <= n; i++)
if (st[i][j - 1].v < st[i + (1 << (j - 1))][j - 1].v) {
st[i][j].v = st[i][j - 1].v;
st[i][j].index = st[i][j - 1].index;
} else {
st[i][j].v = st[i + (1 << (j - 1))][j - 1].v;
st[i][j].index = st[i + (1 << (j - 1))][j - 1].index;
}
return;
}
int work_v(int l, int r) {
int k = log2(r - l + 1);
return min(st[l][k].v, st[r - (1 << k) + 1][k].v);
}
int work_index(int l, int r) {
int k = log2(r - l + 1);
return st[l][k].v < st[r - (1 << k) + 1][k].v ? st[l][k].index : st[r - (1 << k) + 1][k].index;
}
int main() {
long long ans = 0;
scanf("%lld %lld %lld %lld", &n, &m, &L, &R);
for (int i = 1; i <= n; i++) {
scanf("%lld", &a[i]);
sum[i] = sum[i - 1] + a[i];
st[i][0].v = sum[i];
st[i][0].index = i;
}
RMQ();
for (int i = 1; i <= n; i++) {
int sl = max(0, int(i - R)), sr = i - L;
if (sl > sr || sr < 0)
continue;
data cnt;
cnt.r = sr;
cnt.l = sl;
cnt.r_ = i;
cnt.l_ = work_index(cnt.l, cnt.r);
cnt.t = work_v(cnt.l, cnt.r);
q.push(cnt);
}
while (m-- && !q.empty()) {
data cnt = q.top();
q.pop();
ans += sum[cnt.r_] - cnt.t;
data cnt2;
cnt2 = cnt;
cnt2.l = cnt.l;
cnt2.r = cnt.l_ - 1;
if (cnt2.l <= cnt2.r) {
cnt2.t = work_v(cnt2.l, cnt2.r);
cnt2.l_ = work_index(cnt2.l, cnt2.r);
q.push(cnt2);
}
cnt2 = cnt;
cnt2.l = cnt.l_ + 1;
cnt2.r = cnt.r;
if (cnt2.l <= cnt2.r) {
cnt2.t = work_v(cnt2.l, cnt2.r);
cnt2.l_ = work_index(cnt2.l, cnt2.r);
q.push(cnt2);
}
}
printf("%lld", ans);
return 0;
}