2019.10.11考试解题报告
2019.10.11考试解题报告
总结
期望得分:\(100 + 100 + 0\)
实际得分:\(100 +96 + 0\)(原因是\(T2\)满分\(96\))
期望得分与实际得分一致,也算是没写挂了
但是在时间的安排上不是很合理,在\(T1\)上花了很长时间,因为发现自己的线段树\(so\)慢,之后导致去做\(T3\)的时候时间已经不多了
以后还是要合理安排时间
思路
T1
题意:
一个长度为\(n\)的数组,有\(q\)次操作,操作包括三种
分别是单点加,单点修改与整体修改,每次操作之后都要输出数组中所有元素的和。
打了个线段树发现有点慢……裸的线段树根本不行,甚至会\(MLE\)
而且读入还是有点慢……
然后惊人地发现不用线段树就可以……
发现答案不难统计,所以每次进行简单的调整就可以了
用一个数组\(b\)表示每个位置的层数
定义\(sjp\)代表最最先进的那一层(就是当前层。。)
每次3操作都让\(sjp++\),并将\(now\)赋值为\(y\)
如果进行\(1、2\)操作时层数不是\(sjp\),就把\(x\)这个位置的值赋为\(now\)
并把\(b[x]\)赋值为\(sjp\),表示当前\(x\)这个位置的层数已经是\(sjp\)了……
这样一次次更新就行了
T2
题意:
给你一张\(n\)个点\(m\)条边,且边权全为正的有向图,求这张图的最长路,并保证存在最长路
20分
可以试下神奇的最短路算法\(floyd\)
时间复杂度\(O(n^3)\),可以过前\(20\%\)
40分
可以试下\(N\)遍堆优化\(dijkstra\)或者\(SPFA\)(关于\(SPFA\),他死了)
100分
既然保证最长路存在,并且边权全为正,就表明了这张图是个有向无环图(\(DAG\)),所以我们就可以用拓扑排序 + \(DP\)来解决
T3
题意:
给你一张\(n\)个点\(m\)条边的无向图,求图上与每个点最短距离之和最小与最大的两个点,点可以在边上任意位置,问这两个点与每个点最短距离之和是多少。(可以不为整数)
考场上来不及做,也不会做的一道神题
老师下发的题解上说这是一道真正考察选手综合算法能力的题目
但我不会,菜死了
代码
T1
死慢死慢的线段树
//知识点:真·线段树
/*
By:Loceaner
*/
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
inline int read() {
char c = getchar();
int x = 0, f = 1;
for( ; !isdigit(c); c = getchar()) if(c == '-') f = -1;
for( ; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + (c ^ 48);
return x * f;
}
const int N = 1e7 + 11;
#define lson rt << 1
#define rson rt << 1 | 1
struct node {
int l, r, sum, lazy;
} t[N << 2];
long long ans = 0;
inline void pushup(int rt) {
t[rt].sum = t[lson].sum + t[rson].sum;
}
void build(int l, int r, int rt) {
t[rt].l = l, t[rt].r = r;
if(l == r) return;
int mid = (l + r) >> 1;
build(l, mid, lson);
build(mid + 1, r, rson);
}
void bian(int mb, int x, int rt) {//变!
if(t[rt].l == mb && t[rt].r == mb) {
t[rt].sum = x;
return;
}
int mid = (t[rt].l + t[rt].r) >> 1;
if(mb <= mid) bian(mb, x, lson);
else bian(mb, x, rson);
pushup(rt);
}
void jia(int mb, int x, int rt) {//加!
if(t[rt].l == mb && t[rt].r == mb) {
t[rt].sum += x;
return;
}
int mid = (t[rt].l + t[rt].r) >> 1;
if(mb <= mid) jia(mb, x, lson);
else jia(mb, x, rson);
pushup(rt);
}
void update(int L, int R, int x, int rt) {
if(t[rt].l == t[rt].r) {
t[rt].sum = x;
return;
}
int mid = (t[rt].l + t[rt].r) >> 1;
if(mid >= R) update(L, R, x, lson);
else if(L > mid) update(L, R, x, rson);
else {
update(L, mid, x, lson);
update(mid + 1, R, x, rson);
}
pushup(rt);
}
void find(int L, int R, int rt) {
if(t[rt].l == L && t[rt].r == L){
ans += t[rt].sum;
return;
}
int mid = (t[rt].l + t[rt].r) >> 1;
if(mid >= R) find(L, R, lson);
else if(L > mid) find(L, R, rson);
else {
find(L, mid, lson);
find(mid + 1, R, rson);
}
pushup(rt);
}
int n, q;
int main() {
freopen("segmenttree.in", "r", stdin);
freopen("segmenttree.out", "w", stdout);
n = read(), q = read();
build(1, n, 1);
while(q--) {
int opt = read(), x, y;
if(opt == 1) {
x = read(), y = read();
bian(x, y, 1);
}
else if(opt == 2) {
x = read(), y = read();
jia(x, y, 1);
}
else if(opt == 3) {
y = read();
update(1, n, y, 1);
}
ans = 0;
find(1, n, 1);
cout << ans << '\n';
}
return 0;
}
玄学的\(O(q)\)满分做法
/*
By:Loceaner
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXSIZE=50000020;
const int N = 1e7 + 11;
int bufpos;
char buf[MAXSIZE];
int re() {
int val = 0;
for(; buf[bufpos] < '0' || buf[bufpos] > '9'; bufpos ++);
for(; buf[bufpos] >= '0' && buf[bufpos] <= '9'; bufpos ++)
val = val * 10 + buf[bufpos] - '0';
return val;
}
int n, q, a[N], now, b[N], sjp;
ll sum = 0;
int main(){
freopen("segmenttree.in", "r", stdin);
freopen("segmenttree.out", "w", stdout);
buf[fread(buf, 1, MAXSIZE, stdin)] = '\0';
bufpos = 0;
n = re(); q = re();
for(int i = 1; i <= q; i ++){
int opt = re();
if(opt == 1){
int x = re(), y = re();
if(b[x] < sjp) a[x] = now, b[x] = sjp;
//a[x] = y;
sum += y - a[x];
a[x] = y;
cout << sum << '\n';
}
if(opt == 2){
int x = re(), y = re();
if(b[x] < sjp) a[x] = now, b[x] = sjp;
sum += y;
a[x] += y;
cout << sum << '\n';
}
if(opt == 3){
int y = re();
now = y;
sjp++;
sum = y * n;
cout << sum << '\n';
}
}
return 0;
}
T2
考场满分代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXSIZE=50000020; //读入缓存大小,不要改动
const int N = 1e6 + 11;
int bufpos;
char buf[MAXSIZE];
int re(){ //读入一个int类型的整数
int val = 0;
for(; buf[bufpos] < '0' || buf[bufpos] > '9'; bufpos ++);
for(; buf[bufpos] >= '0' && buf[bufpos] <= '9'; bufpos ++)
val = val * 10 + buf[bufpos] - '0';
return val;
}
struct node {
int to, nxt, val;
} e[N << 1];
int n, m;
int head[N], tot;
ll f[N], ans;
inline void add(int from, int to, int val) {
e[++tot].val = val;
e[tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
}
queue <int> q;
int ind[N], seq[N], cnt;
signed main(){
freopen("lpsa.in", "r", stdin);
freopen("lpsa.out", "w", stdout);
buf[fread(buf, 1, MAXSIZE, stdin)] = '\0';
bufpos = 0;
n = re(); m = re();
for(int i = 1; i <= m; i ++){
int u = re(), v = re(), w = re();
add(v, u, w);
ind[u]++;
}
for(int i = 1; i <= n; i++) if(!ind[i]) q.push(i);
while(!q.empty()) {
int u = q.front();
q.pop();
seq[++cnt] = u;
for(int i = head[u]; i; i = e[i].nxt) {
int v = e[i].to;
--ind[v];
if(ind[v] == 0) q.push(v);
}
}
for(int i = 1; i <= cnt; i++) {
int now = seq[i];
for(int j = head[now]; j; j = e[j].nxt) {
int to = e[j].to;
f[to] = max(f[to], f[now] + e[j].val);
}
ans = max(f[now], ans);
}
cout << ans << '\n';
return 0;
}
T3
考场代码没脸放
神奇的正解
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <vector>
#include <map>
#include <complex>
#define lc k << 1
#define rc k << 1 | 1
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const ll mod = 1e9 + 7;
struct edge{
int to, nxt;
ll w;
}e[100005];
int h[1005], cnt;
void addedge(int x, int y, ll w){
cnt++; e[cnt].to = y; e[cnt].w = w; e[cnt].nxt = h[x]; h[x] = cnt;
cnt++; e[cnt].to = x; e[cnt].w = w; e[cnt].nxt = h[y]; h[y] = cnt;
}
int n, m;
ll dis[1005][1005]; int vis[1005];
ll sum[1005];
void spfa(int s){
memset(vis, 0, sizeof(vis));
queue<int> q; dis[s][s] = 0; vis[s] = 1; q.push(s);
while(!q.empty()){
int x = q.front(); q.pop();
for(int i = h[x]; i; i = e[i].nxt){
if(dis[s][e[i].to] > dis[s][x] + e[i].w){
dis[s][e[i].to] = dis[s][x] + e[i].w;
if(!vis[e[i].to]) vis[e[i].to] = 1, q.push(e[i].to);
}
}
vis[x] = 0;
}
}
double mn = 1e17, mx = 0;
double st[1005];
void sol(int x, int y, ll w){
double res = sum[x];
for(int i = 1; i <= n; i ++){
st[i] = 1.0 * (dis[y][i] - dis[x][i] + w) / 2.0;
}
sort(st + 1, st + n + 1);
double d = 0, tmp; ll k = n;
for(int i = 1; i <= n; i ++){
tmp = st[i] - d;
res = res + tmp * k;
d = st[i]; k -= 2;
mn = min(mn, res);
mx = max(mx, res);
}
}
int main(){
freopen("foodshop.in", "r", stdin);
freopen("foodshop.out", "w", stdout);
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++) dis[i][j] = 1e17;
}
for(int i = 1; i <= m; i ++){
int x, y; ll w;
scanf("%d%d%lld", &x, &y, &w);
addedge(x, y, w);
}
for(int i = 1; i <= n; i ++){
spfa(i);
}
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= n; j ++){
sum[i] += dis[i][j];
}
mn = min(mn, (double)sum[i]);
mx = max(mx, (double)sum[i]);
}
for(int x = 1; x <= n; x ++){
for(int i = h[x]; i; i = e[i].nxt){
sol(x, e[i].to, e[i].w);
}
}
printf("%.1lf %.1lf\n", mn, mx);
return 0;
}