|
这题做得人特别少,但实际上就是很普通的动态规划。
思路: 由于飞到某个点的时候,后面的行程跟前面的行程没有什么联系,所以开一个二维数组 f[K][N], f[i][j] = { 从第 j 个点,第 i 个时刻开始飞行直到终点,所需要的最小花费 }
然后就从后往前推就可以了。
#include <stdio.h>
#include <string.h>

#define MAX_N 16
#define MAX_D 32
#define INFINITE 100000

 struct node {
int arr[MAX_D], cnt;
};
struct node map[MAX_N][MAX_N];
int N, K;

__inline void input()
  {
int i, j, k;
struct node *t;

 for (i = 1; i <= N; i++) {
 for (j = 1; j <= N; j++) {
if (i == j)
continue;
t = &map[i][j];
scanf("%d", &t->cnt);
for (k = 0; k < t->cnt; k++)
scanf("%d", &t->arr[k]);
}
}
}

__inline int min(int a, int b)
  {
return a < b ? a : b;
}

__inline void solve(int sc)
  {
int dp[2][MAX_N], *cur, *nxt, i, j, k, val;
struct node *t;

memset(dp, 0, sizeof(dp));
dp[0][N] = 1;
 for (i = K - 1; i >= 0; i--) {
cur = dp[(K - 1 - i) & 1];
nxt = dp[(K - i) & 1];
 for (j = 1; j <= N; j++) {
nxt[j] = 0;
 for (k = 1; k <= N; k++) {
if (j == k || !cur[k])
continue;
t = &map[j][k];
val = t->arr[i % t->cnt];
if (!val)
continue;
val += cur[k];
if (!nxt[j] || val < nxt[j])
nxt[j] = val;
}
}
}
printf("Scenario #%d\n", sc);
if (nxt[1])
printf("The best flight costs %d.\n\n", nxt[1] - 1);
else
printf("No flight possible.\n\n");
}

int main()
  {
int i;

freopen("e:\\test\\in.txt", "r", stdin);

 for (i = 1; scanf("%d%d", &N, &K), N; i++) {
input();
solve(i);
}
}

摘要: 思路:这题就是平常玩的那种推箱子的游戏。不过简化了一下,只是推一个箱子而已。用 bfs 来做,搜索树里面的节点,也就是状态,可以定义为:1. 箱子的坐标2. 上一次推完之后,人要走多少步才能到达箱子的上、下、左、右侧。如果到达不了,值则为无穷大。这样,状态转移的时候。就首先看是否能向某个方向推。如果能的话,就推一下。然后对人进行一次 bfs ,看下此时到达箱子的各个侧要走多少步。就可以生成一个新的... 阅读全文
思路: 一开始想到用线段树来做,但是发现坐标范围异常的大,放一个都勉勉强强,更不用说几个了! 想了一下,发现有一个至关重要的条件“不存在覆盖的情况”。 那就没必要用线段树了,因为压根就没必要解决覆盖问题。 可以用一种取巧的方法解决这题。  对于每个矩形,首先把它 y 方向的两条边抽取出来。 对于所有矩形的 y 方向的边,先按照 x 排序,然后按照顶端的 y 坐标排序。  然后对于位于同一 x 坐标的边,找出所有首尾相接或者有交集的边。 那么这些边对应的矩形必定要排除。 对于 x 方向的边,作同样的处理。 排除完之后,剩下的矩形就是可以答案了。 代码 500 多ms。。
#include <stdio.h>
#include <stdlib.h>

#define MAX_N 25032

 struct node {
int barn, start, end, idx;
};
struct node vert[MAX_N * 2], hori[MAX_N * 2];
char cannot[MAX_N];
int N, ans;

__inline void add_node(struct node *t, int barn, int start, int end, int idx)
  {
t->barn = barn;
t->start = start;
t->end = end;
t->idx = idx;
}

int cmp_node(const void *a, const void *b)
  {
struct node *p, *q;
p = (struct node *)a;
q = (struct node *)b;
if (p->idx != q->idx)
return p->idx - q->idx;
return p->start - q->start;
}

__inline void disable_barn(int barn)
  {
 if (!cannot[barn]) {
cannot[barn] = 1;
ans--;
}
}

__inline void calc(struct node *arr, int len)
  {
int i, idx, end, cnt, first;

i = 0;
 while (i < len) {
idx = arr[i].idx;
end = arr[i].end;
first = i;
cnt = 0;
i++;
 while (i < len && arr[i].idx == idx && arr[i].start <= end) {
if (arr[i].end > end)
end = arr[i].end;
disable_barn(arr[i].barn);
cnt++;
i++;
}
if (cnt)
disable_barn(arr[first].barn);
}
}

int main()
  {
int i, top, left, bottom, right;

freopen("e:\\test\\in.txt", "r", stdin);

scanf("%d", &N);
ans = N;
 for (i = 0; i < N; i++) {
scanf("%d%d%d%d", &left, &bottom, &right, &top);
add_node(&vert[i * 2], i, bottom, top, left);
add_node(&vert[i * 2 + 1], i, bottom, top, right);
add_node(&hori[i * 2], i, left, right, top);
add_node(&hori[i * 2 + 1], i, left, right, bottom);
}
qsort(vert, N * 2, sizeof(vert[0]), cmp_node);
qsort(hori, N * 2, sizeof(hori[0]), cmp_node);
calc(vert, N * 2);
calc(hori, N * 2);
printf("%d\n", ans);

return 0;
}

摘要: 此题只有130人solved!也算小牛题了,刚开始看到的时候,打算不做了的,但后来想了一下,发现有一点点思路。经过好几个小时的奋战,居然做出来了!那感觉非常爽!思路:首先此题的变态之处是,要求比较的是排名,就不是单纯的字符串匹配了。如果每次都重新求排名然后跟pattern比较,复杂度 O(NK),八成会超时。关键是:一,不能每次都重新求排名二,不能逐个逐个的和pattern做比较看来也只有动态规... 阅读全文
思路: 看到这题,第一个想到的方法就是枚举 sqrt(2), sqrt(3), sqrt(4) 。。,然后sprintf出来,再比较字符串。 显然,这种方法比较低级啦。 仔细想了下,发现如果 x.123... 这个数字的平方是一个整数的话,那必然 sqr(x.124) > ceil(sqr(x.123)) [sqr = 求平方, ceil = 向上取整] 所以,就可以从小到大枚举它的整数部分 x ,遇到第一个满足结果的 x,就是答案了。
代码 0ms AC
#include <stdio.h>
#include <math.h>

double A, P, B;
int L;

__inline double sqr(double i)
  {
return i * i;
}

 double pow_1[] = {
1, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10,
};

int main()
  {
double i, j;
int d;

freopen("e:\\test\\in.txt", "r", stdin);

scanf("%d%d", &L, &d);
P = pow_1[L];
B = P * d;
 for (A = 1; ; A++) {
i = (__int64)sqr(A + B) + 1;
j = sqr(A + B + P);
if (j > i)
break;
}
printf("%I64d\n", (__int64)i);

return 0;
}

摘要: 这个题目立意很好,但是就是数据比较无语了。O(N^3)的算法都能跑得比 O(N^2LgN)的快。代码写很长,这份应该算比较烂了,连自己都不知道代码的时间复杂度是多少!最终170ms AC,速度不快,比几百行的O(N^3)代码要慢很多。。。注意:用分数保存斜率,可以不触及精度问题,而且还比较方便。提交了很多次都WA,不知道问题所在,于是还写了一个脚本来测数据,然后发现了问题所在。附带脚本和测试数据... 阅读全文
有人说,宫崎骏只拍过一部片子,叫做《我们的纯真与失落》。
思路: 开四个树状数组。。 arr_x,arr_y,arr_xy,arr_cnt 分别统计y轴下:x的和、y的和、x*y的和、点的个数。 把点按照x排序,x越大的点出现得越晚。 从前往后推,每出现一个新的点的时候: Step1,将该点加入到四个数组中。 Step2,对于高于它的点,面积增量为 x*sum(y) - sum(x*y)。 Step3,对于低于它的点,面积增量为 sum(y) * (cnt * x - sum(x)) 最终得出结果。复杂度O(NlgN)。代码 63ms。 注意: 需要用int64保存数组元素
#include <stdio.h>

#define MAX_X 20032
#define MAX_Y 20032

int cow[MAX_X], left, top, N;
__int64 arr_x[MAX_Y], arr_y[MAX_Y], arr_xy[MAX_Y], arr_cnt[MAX_Y];

__inline int lowbit(int i)
  {
return i & (i ^ (i - 1));
}

__inline __int64 sum(__int64 *arr, int i)
  {
__int64 s;
for (s = 0; i; i -= lowbit(i))
s += arr[i];
return s;
}

__inline void insert(__int64 *arr, int i, __int64 val)
  {
for (; i <= top; i += lowbit(i))
arr[i] += val;
}

int main()
  {
int i, x, y;
__int64 s, sx, sy, sxy, c;

freopen("e:\\test\\in.txt", "r", stdin);

scanf("%d", &N);
left = MAX_X;
 for (i = 0; i < N; i++) {
scanf("%d%d", &y, &x);
if (x < left)
left = x;
if (y > top)
top = y;
cow[x] = y;
}

s = 0;
x = left - 1;
 for (i = 0; i < N; i++) {
for (x++; !cow[x]; x++);
y = cow[x];
insert(arr_x, y, x);
insert(arr_y, y, y);
insert(arr_xy, y, x * y);
insert(arr_cnt, y, 1);
c = sum(arr_cnt, y - 1);
sx = sum(arr_x, y - 1);
s += c*x*y - sx*y;
sy = sum(arr_y, top) - sum(arr_y, y - 1);
sxy = sum(arr_xy, top) - sum(arr_xy, y - 1);
s += x*sy - sxy;
}

printf("%I64d\n", s);

return 0;
}

思路: 如果之前出现过长度为 len 的子序列。假设该子序列出现在 [a, b] 之间。 那如果存在 1, 2, ... K 任意一个数字出现在 [a, b] 之间,则必然存在一个长度为 len + 1 的非子序列。
代码: 从后往前推。用的是链表。94ms AC。 速度一般,还是不知道那些 0ms 是怎么搞出来的。 有人说可以从前往后推,可能会快一点吧。
#include <stdio.h>

#define MAX_N 100032
#define MAX_K 10032

 struct node {
int idx;
struct node *next;
};
struct node nodes[MAX_N], *pos[MAX_K];
int N, K, left;

int main()
  {
int i, j, len;

freopen("e:\\test\\in.txt", "r", stdin);
scanf("%d%d", &N, &K);
 for (i = 0; i < N; i++) {
scanf("%d", &j);
nodes[i].idx = i;
nodes[i].next = pos[j];
pos[j] = &nodes[i];
}

left = N + 1;
 for (len = 1; len <= N; len++) {
j = left;
 for (i = 1; i <= K; i++) {
while (pos[i] && pos[i]->idx >= left)
pos[i] = pos[i]->next;
if (!pos[i])
break;
if (pos[i]->idx < j)
j = pos[i]->idx;
}
if (i <= K)
break;
left = j;
}
printf("%d\n", len);

return 0;
}

思路: 首先每条路径的值都可以分解一下质因数,就可以表示为多个质数的幂相乘的形式, 比如 2^6 * 3^8 * 17^22 * 23^1。 三个数字a, b, c求最大公约数,分解完质因数后: 如果a拥有2^8,b拥有2^10,c拥有2^4。那最大公约数必然拥有2^4,取最小的一个。 对于每个质数 2, 3, 5, 7。。都是这个道理。 如果是求最小公倍数,在刚刚的例子里,就是取最大的一个了。 在点之间行走的过程,可以这样来看。在点1的时候GCF的值是所有质数的最大次幂的乘积。 GCF的值必定是越走越小。 每经过一条路径,CGF各个质因数的幂都必须小于等于路径的对应的值。 就好比路径就只能容纳这么大的流量。然后到达点2的时候,看看哪条路径的流量最大。 看起来像最大流问题,但不是最大流问题。 我们没办法遍历一次图,就求出哪条路径的流量最大。 但由于路径的权值最大才2000,质因数的幂最大也只有11(2^11 = 2048),大不了每个幂都试一次。 用二分法就可以了。 对于每一个质数,求到达点2 的时候的最大的幂。 最后再乘起来,就是答案了。 可见这种方法还是很巧妙的,效率也很高,0ms AC。 注意: 不需要高精度。但需要用__int64来保存答案。
#include <stdio.h>

#define MAX_W 2048
#define MAX_N 32

int N, visit[MAX_N], map[MAX_N][MAX_N], tm;
int prime[MAX_W], prime_cnt, max_cnt[MAX_W];

int dfs(int idx, int val, int cnt)
  {
int i, j, k;

if (idx == 2)
return 1;

visit[idx] = tm;
 for (i = 1; i <= N; i++) {
if (visit[i] == tm)
continue;
j = map[idx][i];
for (k = 0; j && !(j % val); k++)
j /= val;
if (k < cnt)
continue;
if (dfs(i, val, cnt))
return 1;
}

return 0;
}

__inline int calc(int val, int r)
  {
int l, m;

l = 0;
 while (l <= r) {
m = (l + r) / 2;
tm++;
if (dfs(1, val, m))
l = m + 1;
else
r = m - 1;
}

return r;
}

int main()
  {
int i, j, val, p, cnt;
__int64 r;

freopen("e:\\test\\in.txt", "r", stdin);

prime[prime_cnt++] = 2;
 for (i = 3; i < MAX_W; i++) {
for (j = 0; j < prime_cnt && (i % prime[j]); j++);
if (j == prime_cnt)
prime[prime_cnt++] = i;
}
scanf("%d", &N);
for (i = 1; i <= N; i++)
for (j = 1; j <= N; j++)
scanf("%d", &map[i][j]);
 for (i = 2; i <= N; i++) {
val = map[1][i];
 for (j = 0; j < prime_cnt && val >= 1; j++) {
p = prime[j];
for (cnt = 0; !(val % p); cnt++)
val /= p;
if (cnt > max_cnt[j])
max_cnt[j] = cnt;
}
}
 for (i = 0; i < prime_cnt; i++) {
if (!max_cnt[i])
continue;
max_cnt[i] = calc(prime[i], max_cnt[i]);
}

r = 1;
 for (i = 0; i < prime_cnt; i++) {
if (!max_cnt[i])
continue;
for (cnt = 0; cnt < max_cnt[i]; cnt++)
r *= prime[i];
}
printf("%I64d\n", r);

return 0;
}

|