前4道水题就不说了,其中我做了C题,1Y,小心仔细写代码并且提交之前得确认无误后提交才能减少出错率。

结果后面2题都由波神做掉,学长带我们飞~

终榜 官方题解

 

ZOJ 3946 Highway Project(K题)

题意:求到所有点最短花费时间总和以及在这前提下的走过的路的最小花费金钱

分析:首先最短路跑一个,然后在d[v] == d[u] + time的一些边上选择最小金钱,注意这里只要cost[v] = cost不用累加cost[u]。就是跑了两次最短路。

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;
struct Edge {
int v, t, c, nex;
};
Edge edge[N<<1];
int head[N];
ll _time[N];
int cost[N];
bool vis[N];
int n, m, tote; void SPFA(int s, ll &sumt, ll &sumc) {
memset (vis, false, sizeof (vis));
memset (_time, INF, sizeof (_time));
vis[s] = true; _time[s] = 0;
std::queue<int> que; que.push (s);
while (!que.empty ()) {
int u = que.front (); que.pop ();
vis[u] = false;
for (int i=head[u]; ~i; i=edge[i].nex) {
Edge &e = edge[i];
if (_time[e.v] > _time[u] + e.t) {
_time[e.v] = _time[u] + e.t;
if (!vis[e.v]) {
vis[e.v] = true;
que.push (e.v);
}
}
}
}
memset (vis, false, sizeof (vis));
memset (cost, INF, sizeof (cost));
vis[s] = true; cost[s] = 0;
que.push (s);
while (!que.empty ()) {
int u = que.front (); que.pop ();
vis[u] = false;
for (int i=head[u]; ~i; i=edge[i].nex) {
Edge &e = edge[i];
if (_time[e.v] == _time[u] + e.t && cost[e.v] > e.c) {
cost[e.v] = e.c;
if (!vis[e.v]) {
vis[e.v] = true;
que.push (e.v);
}
}
}
}
for (int i=1; i<n; ++i) {
sumt += _time[i];
sumc += cost[i];
}
} void add_edge(int u, int v, int t, int c) {
edge[tote].v = v; edge[tote].t = t; edge[tote].c = c;
edge[tote].nex = head[u]; head[u] = tote++;
} void init_edge() {
memset (head, -1, sizeof (head));
tote = 0;
} int test() {
return 10;
} int main() {
std::cerr << test () << '\n';
int T; scanf ("%d", &T);
while (T--) {
scanf ("%d%d", &n, &m);
init_edge ();
for (int i=0; i<m; ++i) {
int u, v, t, c;
scanf ("%d%d%d%d", &u, &v, &t, &c);
add_edge (u, v, t, c);
add_edge (v, u, t, c);
}
ll sumt = 0, sumc = 0;
SPFA (0, sumt, sumc);
printf ("%lld %lld\n", sumt, sumc);
}
return 0;
}

ZOJ 3939 The Lucky Week(D题)

题意:Monday是1日或11日或21日的那天是lucky week day,给了开始日期,问从该天起第N天是哪天。(波神一开始就说是循环节,我一听是循环节感觉很陌生,一脸懵逼,当时还看错题意,Monday还看漏了,赛后补了,发现还是很好做的。)

分析:打表找规律,发现400年一个周期,一个周期有2058天lucky day。对于询问只要取模一下,再400乘回来就行了。

#include <bits/stdc++.h>

typedef long long ll;
int _month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; bool judge(int y) {
if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) {
return true;
} else {
return false;
}
} struct Data {
int y, m, d;
};
std::vector<Data> vec; void init() {
int day = 1;
//从注释的代码得知只要处理出400年的循环节
for (int i=1753; i<=1753+399; ++i) {
for (int j=1; j<=12; ++j) {
int mday = _month[j];
if (judge (i) && j == 2) {
mday++;
}
while (day <= mday) {
if (day == 1 || day == 11 || day == 21) {
vec.push_back ((Data) {i, j, day});
}
day += 7;
}
day -= mday;
}
}
//calc
/*
for (int i=0; i<vec.size (); ++i) {
bool flag = true;
for (int l=0, r=i+1; l<=i && r<vec.size (); ++l, ++r) {
if (vec[l].m != vec[r].m || vec[l].d != vec[r].d) {
flag = false;
break;
}
}
if (flag) {
printf ("i: %d\n", i); //i + 1 = 2058个luky day
//从以下得知循环节是400年
printf ("[%d,%d,%d]\n", vec[0].y, vec[0].m, vec[0].d);
printf ("[%d,%d,%d]\n", vec[i+1].y, vec[i+1].m, vec[i+1].d);
printf ("[%d,%d,%d]\n", vec[2*i+2].y, vec[2*i+2].m, vec[2*i+2].d);
return ;
}
}
*/
} int main() {
init ();
int T; scanf ("%d", &T);
while (T--) {
int y, m, d; scanf ("%d%d%d", &y, &m, &d);
int n; scanf ("%d", &n);
int sz = vec.size (); //2058
int ady = 0; //add year 1
while (y >= 1753 + 400) {
y -= 400;
ady++;
}
ady += (n - 1) / sz; //add year 2
int add = (n - 1) % sz;
ll ty = y, tm = m, td = d;
for (int i=0; i<sz; ++i) {
if (y == vec[i].y && m == vec[i].m && d == vec[i].d) {
int ti = i + add;
while (ti >= sz) {
ti -= sz;
ady++;
}
ty = vec[ti].y + 1ll * ady * 400;
tm = vec[ti].m;
td = vec[ti].d;
break;
}
}
printf ("%lld %lld %lld\n", ty, tm, td);
}
return 0;
}

  

05-11 11:10