2022 CSP-S 补题
P8817 [CSP-S 2022] 假期计划
最暴力的想法是 预处理最短路并枚举四个点 考虑优化
可以枚举 \(b\) 和 \(c\) 来降低复杂度
对于每一个点 处理和它距离小于等于 \(k+1\) 而且能在 \(k+1\) 步内到达的点的前 \(3\) 大的点(前 \(3\) 大是为了和除了这两个点以外的另外两个点区分开) 如果符合点不重复就加入即可
总的时间复杂度为 \(O(n^2)\) ( \(set\) 的复杂度约为常数 可以忽略 )
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define print(x) cout<<#x<<' '<<x<<endl
#define int long long
const int N = 2500 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , m , k , val[N] , q[10000000] , head , tail , dis[N][N] , vis[N] , maxx;
struct node { int id , val; friend bool operator < ( const node &a , const node &b ) { return a.val < b.val; } };
set<node> s[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
void bfs ( int s )
{
memset ( dis[s] , inf , sizeof dis[s] );
memset ( vis , 0 , sizeof vis );
head = 1 , tail = 0;
q[++tail] = s , dis[s][s] = 0 , vis[s] = 1;
while ( head <= tail )
{
int u = q[head++];
for ( auto v : e[u] )
if ( dis[s][v] > dis[s][u] + 1 )
{
dis[s][v] = dis[s][u] + 1;
if ( !vis[v] ) vis[v] = 1 , q[++tail] = v;
}
}
}
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , k = read();
for ( int i = 2 ; i <= n ; i ++ ) val[i] = read();
for ( int i = 1 , u , v ; i <= m ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
for ( int i = 1 ; i <= n ; i ++ ) bfs ( i );
for ( int i = 2 ; i <= n ; i ++ )
for ( int j = 2 ; j <= n ; j ++ )
if ( i != j )
{
if ( dis[i][j] <= k + 1 && dis[1][j] <= k + 1 ) s[i].insert({j,val[j]});
if ( s[i].size() > 3 ) s[i].erase(s[i].begin());
}
for ( int b = 2 ; b <= n ; b ++ )
for ( int c = 2 ; c <= n ; c ++ )
for ( auto [a,tmp1] : s[b] )
for ( auto [d,tmp2] : s[c] )
if ( a != b && a != c && a != d && b != c && b != d && c != d && dis[b][c] <= k + 1 )
maxx = max ( maxx , val[a] + val[b] + val[c] + val[d] );
cout << maxx << endl;
return 0;
}
P8818 [CSP-S 2022] 策略游戏
对于小 \(L\) 的策略有四种情况:正数最大值 正数最小值 负数最大值 负数最大值
然后小 \(Q\) 相对应的策略就是小 \(L\) 策略的反向 经过讨论可得 记录整个 \(b\) 序列最大值和最小值即可
\(6\) 个 \(st\) 表来分类讨论即可
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define print(x) cout<<#x<<' '<<x<<endl
#define int long long
#define getchar() cin.get()
const int N = 1e5 + 5;
const int M = 25;
const int inf = LONG_LONG_MAX;
// char buf[1<<24] , *p1 , *p2;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , q;
int a[N] , b[N] , maxxa[N][M] , minna[N][M] , zminna[N][M] , fmaxxa[N][M] , maxxb[N][M] , minnb[N][M];
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , q = read();
for ( int i = 1 ; i <= n ; i ++ )
{
a[i] = read() , maxxa[i][0] = minna[i][0] = a[i];
zminna[i][0] = ( a[i] >= 0 ) ? a[i] : inf , fmaxxa[i][0] = ( a[i] < 0 ) ? a[i] : -inf;
}
for ( int i = 1 ; i <= m ; i ++ ) b[i] = read() , maxxb[i][0] = minnb[i][0] = b[i];
for ( int j = 1 ; j <= __lg(n) ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= n ; i ++ )
{
maxxa[i][j] = max ( maxxa[i][j-1] , maxxa[i+(1<<j-1)][j-1] );
minna[i][j] = min ( minna[i][j-1] , minna[i+(1<<j-1)][j-1] );
zminna[i][j] = min ( zminna[i][j-1] , zminna[i+(1<<j-1)][j-1] );
fmaxxa[i][j] = max ( fmaxxa[i][j-1] , fmaxxa[i+(1<<j-1)][j-1] );
}
for ( int j = 1 ; j <= __lg(m) ; j ++ )
for ( int i = 1 ; i + ( 1 << j ) - 1 <= m ; i ++ )
{
maxxb[i][j] = max ( maxxb[i][j-1] , maxxb[i+(1<<j-1)][j-1] );
minnb[i][j] = min ( minnb[i][j-1] , minnb[i+(1<<j-1)][j-1] );
}
for ( int i = 1 ; i <= q ; i ++ )
{
int l1 = read() , r1 = read() , l2 = read() , r2 = read();
int k1 = __lg(r1-l1+1) , k2 = __lg(r2-l2+1);
int maxa = max ( maxxa[l1][k1] , maxxa[r1-(1<<k1)+1][k1] );
int mina = min ( minna[l1][k1] , minna[r1-(1<<k1)+1][k1] );
int zmina = min ( zminna[l1][k1] , zminna[r1-(1<<k1)+1][k1] );
int fmaxa = max ( fmaxxa[l1][k1] , fmaxxa[r1-(1<<k1)+1][k1] );
int maxb = max ( maxxb[l2][k2] , maxxb[r2-(1<<k2)+1][k2] );
int minb = min ( minnb[l2][k2] , minnb[r2-(1<<k2)+1][k2] );
int ans = -inf;
// print(maxa) , print(mina) , print(zmina) , print(fmaxa) , print(maxb) , print(minb);
ans = max ( ans , maxa * ( maxa >= 0 ? minb : maxb ) );
ans = max ( ans , mina * ( mina >= 0 ? minb : maxb ) );
if ( zmina != inf ) ans = max ( ans , zmina * minb );
if ( fmaxa != -inf ) ans = max ( ans , fmaxa * maxb );
cout << ans << endl;
}
return 0;
}
P8819 [CSP-S 2022] 星战
\(70pts\) 暴力:数据分治
首先 记录每一个点的出度为 \(cd[i]\) 那么答案合法当且仅当 所有点的出度都为 \(1\)
对于 \(\le 1000\) 的点 我们可以直接对于四个操作依次遍历出边并标记出边(对于 \(2,4\) 操作建反向边即可) 统计出度即可
那么对于没有 \(2\) 操作和 \(4\) 操作的点 我们考虑用一个全局变量来记录不合法的点的个数来做到 \(O(q)\) 的复杂度
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define print(x) cout<<#x<<' '<<x<<endl
// #define getchar() cin.get()
char buf[1<<24] , *p1 , *p2;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
const int N = 1e6 + 5;
const int inf = 0x3f3f3f3f;
int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , q , cd[N] , ntot;
vector<pii> e[N];
inl void add ( int u , int v , int w ) { e[u].eb(v,w); }
void solve1()
{
ntot = n;
for ( int i = 1 , u , v ; i <= m ; i ++ )
{
u = read() , v = read();
++ cd[u];
if ( cd[u] == 1 ) -- ntot;
if ( cd[u] == 2 ) ++ ntot;
}
q = read();
for ( int i = 1 ; i <= q ; i ++ )
{
int op = read();
if ( op == 2 || op == 4 ) { for ( int j = i ; j <= q ; j ++ ) cout << "NO" << endl; return; }
if ( op == 1 )
{
int u = read() , v = read();
-- cd[u];
if ( cd[u] == 0 ) ++ ntot;
if ( cd[u] == 1 ) -- ntot;
}
else
{
int u = read() , v = read();
++ cd[u];
if ( cd[u] == 1 ) -- ntot;
if ( cd[u] == 2 ) ++ ntot;
}
cout << ( ntot == 0 ? "YES" : "NO" ) << endl;
}
}
void solve2()
{
for ( int i = 1 , u , v ; i <= m ; i ++ ) u = read() , v = read() , add ( v , u , 1 ) , ++ cd[u];//建立反向边 这样题中的入度就改为了出度
q = read();
for ( int i = 1 ; i <= q ; i ++ )
{
int op = read();
if ( op == 1 )
{
int u = read() , v = read();
for ( auto &p : e[v] ) if ( p.fi == u ) p.se = 0 , -- cd[u];
}
if ( op == 2 )
{
int u = read();
for ( auto &p : e[u] ) if ( p.se != 0 ) p.se = 0 , -- cd[p.fi];
}
if ( op == 3 )
{
int u = read() , v = read();
for ( auto &p : e[v] ) if ( p.fi == u ) p.se = 1 , ++ cd[u];
}
if ( op == 4 )
{
int u = read();
for ( auto &p : e[u] ) if ( p.se == 0 ) p.se = 1 , ++ cd[p.fi];
}
int flag = 1;
for ( int j = 1 ; j <= n ; j ++ ) if ( cd[j] != 1 ) flag = 0;
cout << ( flag == 1 ? "YES" : "NO" ) << endl;
}
}
/*
3 6
2 3
2 1
1 2
1 3
3 1
3 2
11
1 3 2
1 2 3
1 1 3
1 1 2
3 1 3
3 3 2
2 3
1 3 1
3 1 3
4 2
1 3 2
*/
signed main ()
{
// freopen("a.in" , "r" , stdin );
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read();
if ( n > 1000 ) solve1();
else solve2();
return 0;
}
P8820 [CSP-S 2022] 数据传输
数据分治打部分分()
\(k=1\) 显然树剖维护即可
\(n\le 2000\) \(dfs\) 先跑一遍两点距离 对于所有距离 \(\le k\) 的点对建边 跑一遍 \(dijkstra\) 即可 (\(n^2logn\) 过 \(2000\) 确实很轻松 应该改一改观念了)
\(k=2\) 考虑 \(dp\)
在树上将这条链提出来拍成平面 然后设置 \(f[i]\) 表示链上到第 \(i\) 个点的答案 那么 \(f[i]\) 可以由前置合法状态转移过来 因为 \(1\) 节点一定会取到 那么我们起点从 \(1\) 开始即可
时间复杂度 \(O(nq)\)
三个数据点分治即为 \(64pts\)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define inl inline
#define eb emplace_back
#define pii pair<int,int>
#define fi first
#define se second
#define print(x) cout<<#x<<' '<<x<<endl
#define int long long
#define getchar() cin.get()
// char buf[1<<24] , *p1 , *p2;
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<24,stdin),p1==p2)?EOF:*p1++)
int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar(); }
return x * f;
}
int n , m , k;
namespace sub1
{
const int N = 1e6 + 5;
int a[N] , sum[N];
int sz[N] , dep[N] , son[N] , fa[N];
int timer , top[N] , rev[N] , pos[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
struct LCA
{
void dfs1 ( int u , int ff )
{
sz[u] = 1 , dep[u] = dep[fa[u] = ff] + 1 , sum[u] = sum[ff] + a[u];
for ( auto v : e[u] )
if ( v ^ ff )
{
dfs1 ( v , u );
sz[u] += sz[v];
if ( sz[v] > sz[son[u]] ) son[u] = v;
}
}
void dfs2 ( int u , int tp )
{
top[u] = tp , pos[u] = ++timer , rev[timer] = u;
if ( son[u] ) dfs2 ( son[u] , tp );
for ( auto v : e[u] ) if ( v ^ fa[u] && v ^ son[u] ) dfs2 ( v , v );
}
int lca ( int u , int v )
{
while ( top[u] != top[v] )
{
if ( dep[top[u]] < dep[top[v]] ) swap ( u , v );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u , v );
return v;
}
int query ( int u , int v )
{
int llca = lca ( u , v );
return sum[u] + sum[v] - sum[llca] - sum[fa[llca]];
}
}T;
void main()
{
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
T.dfs1 ( 1 , 0 ) , T.dfs2 ( 1 , 1 );
for ( int i = 1 ; i <= m ; i ++ )
{
int u = read() , v = read();
cout << T.query ( u , v ) << endl;
}
}
}
namespace sub2
{
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e3 + 5;
int dep[N][N] , dis[N][N] , vis[N] , a[N] , que[N*N];
vector<int> e[N] , ee[N];
inl void add ( int u , int v ) { e[u].eb(v); }
inl void adde ( int u , int v ) { ee[u].eb(v); }
struct node { int id , dis; friend bool operator < ( const node &a , const node &b ) { return a.dis > b.dis; } };
priority_queue<node> q;
void dij ( int s )
{
for ( int i = 1 ; i <= n ; i ++ ) dis[s][i] = inf;
dis[s][s] = a[s];
q.push ( (node) { s , a[s] } );
while ( !q.empty() )
{
int u = q.top().id , ff = q.top().dis; q.pop();
if ( ff != dis[s][u] ) continue;
for ( auto v : ee[u] )
{
if ( dis[s][v] > dis[s][u] + a[v] )
{
dis[s][v] = dis[s][u] + a[v];
q.push ( (node) { v , dis[s][v] } );
}
}
}
}
void dfs ( int s )
{
for ( int i = 1 ; i <= n ; i ++ ) dep[s][i] = inf;
memset ( vis , 0 , sizeof vis );
int head = 1 , tail = 0;
dep[s][s] = 0 , que[++tail] = s , vis[s] = 1;
while ( head <= tail )
{
int u = que[head++];
for ( auto v : e[u] )
if ( dep[s][v] > dep[s][u] + 1 )
{
dep[s][v] = dep[s][u] + 1;
if ( !vis[v] ) vis[v] = 1 , que[++tail] = v;
}
}
}
void main()
{
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
for ( int i = 1 ; i <= n ; i ++ ) dfs ( i );
for ( int i = 1 ; i <= n ; i ++ )
for ( int j = 1 ; j <= n ; j ++ )
if ( i != j && dep[i][j] <= k ) adde ( i , j );
for ( int i = 1 ; i <= n ; i ++ ) dij ( i );
for ( int i = 1 ; i <= m ; i ++ )
{
int u = read() , v = read();
cout << dis[u][v] << endl;
}
}
}
namespace sub3
{
const int inf = 0x3f3f3f3f3f3f3f3f;
const int N = 1e6 + 5;
int a[N] , sum[N] , sta[N] , topp , f[N];
int sz[N] , dep[N] , son[N] , fa[N];
int timer , top[N] , rev[N] , pos[N];
vector<int> e[N];
inl void add ( int u , int v ) { e[u].eb(v); }
struct LCA
{
void dfs1 ( int u , int ff )
{
sz[u] = 1 , dep[u] = dep[fa[u]=ff] + 1 , sum[u] = sum[ff] + a[u];
for ( auto v : e[u] )
if ( v ^ ff )
{
dfs1 ( v , u );
sz[u] += sz[v];
if ( sz[v] > sz[son[u]] ) son[u] = v;
}
}
void dfs2 ( int u , int tp )
{
top[u] = tp , pos[u] = ++timer , rev[timer] = u;
if ( son[u] ) dfs2 ( son[u] , tp );
for ( auto v : e[u] ) if ( v ^ fa[u] && v ^ son[u] ) dfs2 ( v , v );
}
int lca ( int u , int v )
{
while ( top[u] != top[v] )
{
if ( dep[top[u]] < dep[top[v]] ) swap ( u , v );
u = fa[top[u]];
}
if ( dep[u] < dep[v] ) swap ( u , v );
return v;
}
}T;
int solve ( int u , int v )
{
int L = T.lca ( u , v );
int uu = u , vv = v , temp;
topp = 0;
while ( uu != L ) sta[++topp] = uu , uu = fa[uu];
sta[++topp] = L; temp = topp;
while ( vv != L ) sta[++topp] = vv , vv = fa[vv];
reverse ( sta + temp + 1 , sta + topp + 1 );
for ( int i = 1 ; i <= topp ; i ++ ) f[i] = inf;
f[1] = a[sta[1]];
for ( int i = 2 ; i <= topp ; i ++ )
for ( int j = 1 ; j <= min ( i - 1 , k ) ; j ++ )
f[i] = min ( f[i] , f[i-j] + a[sta[i]] );
return f[topp];
}
void main ()
{
for ( int i = 1 ; i <= n ; i ++ ) a[i] = read();
for ( int i = 1 , u , v ; i < n ; i ++ ) u = read() , v = read() , add ( u , v ) , add ( v , u );
T.dfs1 ( 1 , 0 ) , T.dfs2 ( 1 , 1 );
for ( int i = 1 ; i <= m ; i ++ )
{
int u = read() , v = read();
cout << solve ( u , v ) << endl;
}
}
}
/*
7 3 3
1 2 3 4 5 6 7
1 2
1 3
2 4
2 5
3 6
3 7
4 7
5 6
1 2
*/
signed main ()
{
// freopen ( "transmit3.in" , "r" , stdin );
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read() , m = read() , k = read();
if ( k == 1 ) sub1::main();
else if ( k == 2 ) sub3::main();
else if ( n <= 2000 ) sub2::main();
return 0;
}

浙公网安备 33010602011771号