CSP-S模拟3
哼哼哼写题解设密码的都是坏人坏人坏人!!!@Chen_jr
upd: 他公开了,我原谅他了
A. score and rank
连伪贪心都被说中了,不过我发现它伪了qwq!最后一个样例从1到n扫和从n到1扫结果居然是不一样的,而按照伪贪心的设想,它的顺序并不重要,虽然发现了我也不会改,但是我把从1到n和从n到1全都扫了可以多水到15分!
意思就是我如果把6删了,那么也一定不会选-5,相当于要从前面的区间里挑出一些数来捆绑删除,而需要捆绑的原因是再删掉一个前面区间的值就变成了负数,由于从大往小删,临界的情况就是最小的那几个数,所以要用最小的数来“抵消负数的贡献”。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 3;
ll a[maxn], n, S, sum, ans;
multiset<ll> q;
inline ll read()
{
ll x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
int main()
{
freopen("score.in", "r", stdin);
freopen("score.out", "w", stdout);
n = read(); S = read();
for(int i=1; i<=n; i++)
{
a[i] = read();
}
ll sum = 0;
if(S <= 0)
{
for(int i=1; i<=n; i++)
{
if(a[i] > S) ans++;
}
printf("%lld\n", ans);
exit(0);
}
for(int i=1; i<=n; i++)
{
if(a[i] >= 0)
{
sum += a[i]; q.insert(a[i]);
}
else
{
while(sum >= S && !q.empty())
{
auto it = --q.end();
sum -= *it; q.erase(it); ans++;
}
if(sum + a[i] > 0)
{
sum += a[i];
while(a[i] < 0 && !q.empty())
{
a[i] += *q.begin();
q.erase(q.begin());
}
q.insert(a[i]);
}
else
{
q.clear(); sum = 0;
}
}
}
while(sum >= S && !q.empty())
{
auto it = --q.end();
sum -= *it;
q.erase(it);
ans++;
}
printf("%lld\n", ans);
return 0;
}
B. HZOI大作战
先就暴力的跳了个95,不过后来被卡了。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 3;
int n, q, w[maxn], f[maxn], pos[maxn], dep[maxn], ans;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y)
{
a[++len].to = y; a[len].next = head[x];
head[x] = len;
}
void dfs(int u, int fa)
{
//if(u == 1) f[u] = 0;
dep[u] = dep[fa] + 1;
if(w[fa] > w[u])
{
f[u] += f[fa] + 1, pos[u] = fa;
//printf("cmp: w[%d] = %d w[%d] = %d\n", fa, w[fa], u, w[u]);
}
else
{
int x = fa;
while(w[u] >= w[x] && x != 0)
{
//printf("x = %d\n", x);
x = pos[x];
}
if(x == 0) f[u] = 0;
else f[u] = f[x] + 1, pos[u] = x;
}
//printf("f[%d] = %d\n", u, f[u]);
for(int i=head[u]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa) continue;
dfs(v, u);
}
}
int solve(int u, int v, int x)
{
int t = u, an1 = 0;
while(x >= w[t] && dep[t] >= dep[v])
{
t = pos[t];
}
if(dep[t] < dep[v]) return 0;
an1 = f[t] + 1;
while(dep[pos[t]] >= dep[v])
{
t = pos[t];
}
return an1 - f[t];
}
int main()
{
freopen("accepted.in", "r", stdin);
freopen("accepted.out", "w", stdout);
n = read(); q = read();
for(int i=1; i<=n; i++)
{
w[i] = read();
}
for(int i=1; i<n; i++)
{
int x = read(), y = read();
add(x, y); add(y, x);
}
dfs(1, 0);
while(q--)
{
int u = read(), v = read(), x = read();
ans = solve(u, v, x);
printf("%d\n", ans);
}
return 0;
}
然后可以建两个图+倍增一下:
AC 2308ms
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 3;
const int INF = 0x7fffffff;
int up[maxn], dep[maxn], cnt[maxn], n, q, val[maxn], cal[maxn][20];
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
}a1[maxn<<1], a2[maxn];
int head1[maxn], head2[maxn], len1, len2;
void add1(int x, int y)
{
a1[++len1].to = y; a1[len1].next = head1[x];
head1[x] = len1;
}
void add2(int x, int y)
{
a2[++len2].to = y; a2[len2].next = head2[x];
head2[x] = len2;
}
void dfs1(int x, int fa)
{
dep[x] = dep[fa] + 1;
for(int i=head1[x]; i; i=a1[i].next)
{
int to = a1[i].to;
if(to == fa) continue;
int goal = x;
while(val[goal] <= val[to])
{
goal = up[goal];
}
up[to] = goal;
dfs1(to, x);
}
}
void dfs2(int x, int fa)
{
for(int i=head2[x]; i; i=a2[i].next)
{
int to = a2[i].to;
cnt[to] = cnt[x] + 1;
cal[to][0] = up[to];
for(int j=1; j<=19; j++)
{
cal[to][j] = cal[cal[to][j-1]][j-1];
}
dfs2(to, x);
}
}
int main()
{
freopen("accepted.in", "r", stdin);
freopen("accepted.out", "w", stdout);
n = read(); q = read();
for(int i=1; i<=n; i++) val[i] = read();
for(int i=1; i<n; i++)
{
int u = read(), v = read();
add1(u, v); add1(v, u);
}
for(int i=0; i<=19; i++) cal[n+1][i] = n+1;
val[n+1] = 1e9 + 7;
dep[n+1] = 1;
up[1] = n+1;
dfs1(1, n+1);
for(int i=1; i<=n; i++)
{
add2(up[i], i);
}
dfs2(n+1, 0);
while(q--)
{
int u = read(), v = read(), c = read();
int pos = u;
for(int i=19; i>=0; i--)
{
if(val[cal[pos][i]] <= c) pos = cal[pos][i];
}
if(val[pos] <= c) pos = up[pos];
if(dep[pos] < dep[v])
{
printf("0\n"); continue;
}
int lastpos = pos;
for(int i=19; i>=0; i--)
{
if(dep[cal[pos][i]] >= dep[v]) pos = cal[pos][i];
}
printf("%d\n", cnt[lastpos]-cnt[pos]+1);
}
return 0;
}
不过还是Chen_jr的写法简洁!(对于公开题解的人,还是要毫不吝啬我们的mod)
AC 1672ms
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 5e5 + 3;
int dep[maxn], fa[maxn], n, q, w[maxn], cal[maxn][20];
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y)
{
a[++len].to = y; a[len].next = head[x];
head[x] = len;
}
void dfs(int x)
{
if(w[fa[x]] > w[x]) cal[x][0] = fa[x];
else
{
int f = fa[x];
for(int i=19; i>=0; i--)
{
if(cal[f][i] != 0 && w[cal[f][i]] <= w[x])
{
f = cal[f][i];
}
cal[x][0] = cal[f][0];
}
}
for(int i=1; i<=19; i++)
{
cal[x][i] = cal[cal[x][i-1]][i-1];
}
for(int i=head[x]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa[x]) continue;
dep[v] = dep[x] + 1;
fa[v] = x;
dfs(v);
}
}
int main()
{
freopen("accepted.in", "r", stdin);
freopen("accepted.out", "w", stdout);
n = read(); q = read();
for(int i=1; i<=n; i++) w[i] = read();
for(int i=1; i<n; i++)
{
int x = read(), y = read();
add(x, y); add(y, x);
}
dep[1] = 1; dfs(1);
while(q--)
{
int u = read(), v = read(), c = read();
int ans = 0;
if(w[u] <= c)
{
for(int i=19; i>=0; i--)
{
if(cal[u][i] != 0 && w[cal[u][i]] <= c)
{
u = cal[u][i];
}
}
u = cal[u][0];
}
if(dep[u] >= dep[v])
{
ans++;
for(int i=19; i>=0; i--)
{
if(dep[cal[u][i]] >= dep[v])
{
u = cal[u][i]; ans += (1 << i);
}
}
}
printf("%d\n", ans);
}
return 0;
}
C. Delov的旅行
哇我第一眼就预感它不好做然后就跳了,最后5min搞了5分,我的预感也有准的时候。
注意要用log2(n+1)求深度不要忘了log后面的2。
二分一下,先处理子树,由于它是二叉的,如果选择了一条路进出,那剩下的一对孩子就恰好是在中间连接的……总之就是鹤的题解就是了,痕迹明显,比如这是一颗满二叉树……还可以发现如果针对题库上的数据的话,左儿子就是x<<1,右儿子就是x<<1|1,根本就不用建图。当然如果看不见数据的话就要建个图了。
变量名都没改说的就是我
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 231099;
int n;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
ll a, b;
bool operator < (const node &T) const
{
return a == T.a ? b < T.b : a < T.a;
}
};
struct nofe2
{
int next, to, w;
}a[maxn<<1];
int head[maxn], len;
void add(int x, int y, int w)
{
a[++len].to = y; a[len].next = head[x]; a[len].w = w;
head[x] = len;
}
set<node> s[maxn];
node ls[maxn];
bool dfs(int x, int fa, ll mid)
{
s[x].clear();
int lson = 0, rson = 0, vl, vr;
for(int i=head[x]; i; i=a[i].next)
{
int v = a[i].to;
if(v == fa) continue;
if(dfs(v, x, mid) == 0) return 0;
if(lson) rson = v, vr = a[i].w;
else lson = v, vl = a[i].w;
}
if(!lson && !rson)
{
s[x].insert({0, 0}); return 1;
}
if(!rson)
{
for(node now : s[lson])
{
s[x].insert({now.a+vl, now.b+vl});
}
return 1;
}
int cnt = 0;
auto it = s[rson].begin(), en = --s[rson].end();
for(node now : s[lson])
{
while(it != en && (*next(it)).a+now.b+vl+vr <= mid) it++;
if((*it).a+now.b+vl+vr <= mid) ls[++cnt] = {now.a+vl, (*it).b+vr};
}
it = s[lson].begin(), en = --s[lson].end();
for(node now : s[rson])
{
while(it != en && (*next(it)).a+now.b+vl+vr <= mid) it++;
if((*it).a+now.b+vl+vr <= mid) ls[++cnt] = {now.a+vr, (*it).b+vl};
}
if(cnt == 0) return 0;
sort(ls+1, ls+1+cnt);
s[x].insert(ls[1]);
int las = 1;
for(int i=2; i<=cnt; i++)
{
if(ls[i].b < ls[las].b && ls[i].a > ls[las].a)
{
s[x].insert(ls[i]); las = i;
}
}
if(s[x].empty()) return 0;
return 1;
}
int main()
{
freopen("trip.in", "r", stdin);
freopen("trip.out", "w", stdout);
n = read();
for(int i=2; i<=n; i++)
{
int u = read(), w = read();
add(i, u, w); add(u, i, w);
}
ll l = 0, r = 17179870000, ans = r;
while(l <= r)
{
ll mid = (l + r) >> 1;
if(dfs(1, 0, mid)) r = mid - 1, ans = mid;
else l = mid + 1;
}
printf("%lld\n", ans);
return 0;
}
D. gtm和joke的星球
瞎搞的部分分本来有40,可惜我没开2倍边!!就35了。。。
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
const int N = 505;
const ll INF = 1e14;
int n, m, k, pos[maxn];
bool v[maxn];
ll dis[maxn], p[maxn][maxn], ans;
queue<int> q;
vector<int> ext;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
ll w;
}a[N<<1];
int head[maxn], len;
void add(int x, int y, ll w)
{
a[++len].to = y; a[len].next = head[x]; a[len].w = w;
head[x] = len;
}
void spfa(int st)
{
for(int i=1; i<=n; i++) dis[i] = INF;
dis[st] = 0;
q.push(st);
v[st] = 1;
while(!q.empty())
{
int x = q.front(); q.pop();
v[x] = 0;
for(int i=head[x]; i; i=a[i].next)
{
int y = a[i].to;
if(dis[y] > dis[x] + a[i].w)
{
dis[y] = dis[x] + a[i].w;
if(!v[y])
{
q.push(y);
v[y] = 1;
}
}
}
}
}
void solve()
{
int sz = ext.size(), Mp = 0; ll Min = INF;
for(int i=0; i<sz; i++)
{
int x = ext[i];
for(int j=1; j<=k; j++)
{
int y = pos[j];
if(v[y]) continue;
if(p[x][y] < Min)
{
Mp = y; Min = p[x][y];
}
}
}
//printf("Mp = %d Min = %lld\n", Mp, Min);
v[Mp] = 1; ans += Min; ext.push_back(Mp);
}
int main()
{
freopen("steiner.in", "r", stdin);
freopen("steiner.out", "w", stdout);
n = read(); m = read(); k = read();
if(n == 2)
{
for(int i=1; i<=m; i++)
{
int x = read(), y = read(), w = read();
if(x == y) continue;
if(p[x][y]) p[x][y] = p[y][x] = min(p[x][y], (ll)w);
else p[x][y] = p[y][x] = w;
}
if(k == 1)
{
read();
printf("0\n");
}
else if(k == 2)
{
int x = read(), y = read();
printf("%lld\n", p[x][y]);
}
exit(0);
}
if(k == 2)
{
for(int i=1; i<=m; i++)
{
int x = read(), y = read(), w = read();
add(x, y, w); add(y, x, w);
}
int k1 = read(), k2 = read();
spfa(k1);
printf("%lld\n", dis[k2]);
exit(0);
}
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
p[i][j] = INF;
}
p[i][i] = 0;
}
for(int i=1; i<=m; i++)
{
int x = read(), y = read(), w = read();
if(x == y) continue;
if(p[x][y]) p[x][y] = p[y][x] = min(p[x][y], (ll)w);
else p[x][y] = p[y][x] = w;
}
for(int l=1; l<=n; l++)
{
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
if(p[i][j] > p[i][l] + p[l][j])
{
p[i][j] = p[i][l] + p[l][j];
}
}
}
}
if(k == 1)
{
printf("0"); exit(0);
}
/*for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
printf("p[%d][%d] = %lld\n", i, j, p[i][j]);
}
}*/
for(int i=1; i<=k; i++)
{
pos[i] = read();
}
ext.push_back(pos[1]);
v[pos[1]] = 1;
for(int i=1; i<k; i++)
{
solve();
}
printf("%lld\n", ans);
return 0;
}
写正解不开二倍边的结果是TLE 30,数组越界居然还可以T,学到了学到了……
code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 105;
const int N = 505;
const ll INF = 1e14;
int f[maxn][1025], n, m, k, tp[maxn];
bool v[maxn];
typedef pair<int, int> pii;
priority_queue<pii, vector<pii>, greater<pii> > q;
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch^48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to, w;
}a[N<<1];
int head[maxn], len;
void add(int x, int y, int w)
{
a[++len].to = y; a[len].next = head[x]; a[len].w = w;
head[x] = len;
}
void dij(int s)
{
memset(v, 0, sizeof(v));
while(!q.empty())
{
int x = q.top().second;
q.pop();
if(v[x]) continue;
v[x] = 1;
for(int i=head[x]; i; i=a[i].next)
{
int y = a[i].to;
if(f[y][s] > f[x][s] + a[i].w)
{
f[y][s] = f[x][s] + a[i].w;
q.push(make_pair(f[y][s], y));
}
}
}
}
int main()
{
freopen("steiner.in", "r", stdin);
freopen("steiner.out", "w", stdout);
n = read(); m = read(); k = read();
for(int i=1; i<=m; i++)
{
int u = read(), v = read(), w = read();
add(u, v, w); add(v, u, w);
}
for(int i=1; i<=k; i++) tp[i] = read();
memset(f, 0x3f, sizeof(f));
for(int i=1; i<=k; i++) f[tp[i]][1<<(i-1)] = 0;
for(int s=1; s<(1<<k); s++)
{
for(int i=1; i<=n; i++)
{
for(int x=s&(s-1); x; x=s&(x-1))
{
f[i][s] = min(f[i][s], f[i][x]+f[i][s^x]);
}
if(f[i][s] != f[0][0])
{
q.push(make_pair(f[i][s], i));
}
}
dij(s);
}
printf("%d\n", f[tp[1]][(1<<k)-1]);
return 0;
}
A. 游览计划
关于点权版的斯坦纳树,按根合并的时候记得减掉重复点权,还可以记录路径,如果忘了x=s&(x-1)还有一种暴力的写法。
code
//It's not until you fall that you fly.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 2;
const int N = 2e5 + 3;
const int inf = 0x3f3f3f3f;
int a[105], mp[105], b[105][1<<10], f[105][1<<10], pre[105][1<<10];
int n, m, k, pos;
bool vis[105];
priority_queue<pair<int, int> > q;
#define id(x, y) ((x)*m+y)
inline int read()
{
int x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9')
{
if(ch == '-')
{
f = -1;
}
ch = getchar();
}
while(ch >= '0' && ch <= '9')
{
x = (x << 1) + (x << 3) + (ch ^ 48);
ch = getchar();
}
return x * f;
}
struct node
{
int next, to;
}e[2005];
int head[105], len;
void add(int x, int y)
{
e[++len].to = y; e[len].next = head[x];
head[x] = len;
}
void dij(int s)
{
while(q.size())
{
int x = q.top().second; q.pop();
if(vis[x]) continue;
vis[x] = 1;
for(int i=head[x]; i; i=e[i].next)
{
int y = e[i].to;
if(f[y][s] > f[x][s]+a[y])
{
f[y][s] = f[x][s] + a[y];
q.push(make_pair(-f[y][s], y));
pre[y][s] = x;
}
}
}
}
void dfs(int x, int s)
{
if(b[x][s]) return;
b[x][s] = 1;
mp[x] = 1;
if(pre[x][s]!=-1 && f[pre[x][s]][s]+a[x]==f[x][s])
{
int tmp = pre[x][s];
while(tmp!=-1) {dfs(tmp, s); tmp = pre[tmp][s];}
}
for(int j=s&(s-1); j; j=s&(j-1))
{
if(f[x][s]==f[x][j]+f[x][s^j]-a[x])
{
dfs(x, j); dfs(x, s^j); break;
}
}
/*for(int j=s; j>=0; j--)
{
if((j|s)!=s) continue;
if(f[x][s]==f[x][j]+f[x][s-j]-a[x])
{
dfs(x, j); dfs(x, s-j); break;
}
}*/
}
int main()
{
n = read(); m = read(); k = 0, pos = -1;
memset(f, 0x3f, sizeof(f));
memset(pre, -1, sizeof(pre));
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
if(!(a[id(i,j)] = read())) f[id(i,j)][1<<((++k)-1)] = 0, pos = id(i,j);
if(i-1>=0)
{
add(id(i-1,j), id(i,j));
add(id(i,j), id(i-1,j));
}
if(j-1>=0)
{
add(id(i,j-1), id(i,j));
add(id(i,j), id(i,j-1));
}
}
}
for(int s=1; s<(1<<k); s++)
{
for(int i=0; i<n*m; i++)
{
for(int x=s&(s-1); x; x=s&(x-1))
{
f[i][s] = min(f[i][s], f[i][x]+f[i][x^s]-a[i]);
}
/*for(int x=s; x>=0; x--)
{
if((x|s)!=s) continue;
f[i][s] = min(f[i][s], f[i][x]+f[i][s-x]-a[i]);
}*/
vis[i] = 0;
if(f[i][s] != inf) q.push(make_pair(-f[i][s], i));
}
dij(s);
}
if(pos != -1) printf("%d\n", f[pos][(1<<k)-1]);
else printf("0\n");
dfs(pos, (1<<k)-1);
for(int i=0; i<n; i++)
{
for(int j=0; j<m; j++)
{
int x = id(i,j);
if(a[x] && mp[x]) printf("o");
if(a[x] && (!mp[x])) printf("_");
if(!a[x]) printf("x");
}
if(i != n-1) printf("\n");
}
return 0;
}
时光花火,水月星辰