CSP-S 2022 游记

真就游寄

虽然没能正常参加 CSP,但是还是要做一下。
说实话这成绩七级勾本应该是稳了

T1 假期计划 (\(holiday\))2s 512M

\(1\to A\to B\to C\to D\to 1\)
观察这个结构,发现两边是对称的。
预处理出对于所有 \(B\), \(1\to A \to B\) 的最大的 \(A\) 的值。
枚举一下 \(B,C\),直接算贡献。
考虑到点冲突的问题,要记录次大值和次次大值。

int n, m, k;
struct node {
	int t, n;
}e[100005];
int u, v;
int head[100005], head_size;
void ADD(int f, int t) {
	e[++head_size]=(node){t, head[f]};
	head[f]=head_size;
}
int dis[2505][2505];
ll val[2505], ans;
ll maxx[2505][3];
void Change(int i, int j) {
	if(val[maxx[i][0]]<val[j]) {
		maxx[i][2]=maxx[i][1];
		maxx[i][1]=maxx[i][0];
		maxx[i][0]=j;
	}
	else if(val[maxx[i][1]]<val[j]) {
		maxx[i][2]=maxx[i][1];
		maxx[i][1]=j;
	}
	else if(val[maxx[i][2]]<val[j]) {
		maxx[i][2]=j;
	}
}
void BFS(int S) {
	dis[S][S]=0;
	queue<int>q;
	q.push(S);
	while(!q.empty()) {
		int x=q.front(); q.pop();
		for(int i=head[x]; i; i=e[i].n) {
			if(dis[S][e[i].t]>100000000) {
				dis[S][e[i].t]=dis[S][x]+1;
				q.push(e[i].t);
			}
		}
	}
}
ll slove(int x, int y) {
	ll re=-1;
	ll sum=val[x]+val[y];
	for(int i=0; i<=2; ++i) {
		if(maxx[x][i]==0) continue ;
		if(maxx[x][i]==y) continue ;
		for(int j=0; j<=2; ++j) {
			if(maxx[y][j]==0) continue ;
			if(maxx[y][j]==x) continue ;
			if(maxx[y][j]==maxx[x][i]) continue ;
			re=max(re, sum+val[maxx[x][i]]+val[maxx[y][j]]);
		}
	}
	return re;
}
int main(){
	memset(dis, 0x3f, sizeof(dis));
	n=read(); m=read(); k=read();
	for(int i=2; i<=n; ++i) val[i]=read();
	for(int i=1; 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) continue ;
			if(dis[1][j]<=k+1&&dis[j][i]<=k+1) Change(i, j);
		}
	}
	for(int i=2; i<=n; ++i) {
		if(!maxx[i][0]) continue ;
		for(int j=2; j<=n; ++j) {
			if(i==j) continue ;
			if(dis[i][j]>k+1) continue ;
			if(!maxx[j][0]) continue ;
			ans=max(ans, slove(i, j));
		}
	}
	cout<<ans;
}

T2 策略游戏 ( \(game\) ) 1s 512M

\(A\) 选一个数,\(B\) 选择使答案最小的那个。
对于所有 \(A\) 选数之后 \(B\) 选出的最小值取个最大值就行。
其实再多再多也就四种情况。
选正数里最大的或最小的,选负数里最大的或最小的。
那么两个序列,一共 \(4\times 4 = 16\) 种情况,枚举一下就行了。
特别的, \(0\) 作为交界点,即算正数,也算负数。
然后 \(8\) 个 ST 表伺候上就行了。

int n, m, q, a;
int sta[100005][20][4];
int stb[100005][20][4];
int lo[100005];
/*
0正数最大
1正数最小
2负数最大
3负数最小 
*/
int main(){
	n=read(); m=read(); q=read();
	for(int i=1; i<=n; ++i) {
		a=read();
		sta[i][0][0]=sta[i][0][2]=-2e9;
		sta[i][0][1]=sta[i][0][3]=2e9;
		if(a>=0) sta[i][0][0]=sta[i][0][1]=a; 
		if(a<=0) sta[i][0][2]=sta[i][0][3]=a;
	}
	for(int i=1; i<=m; ++i) {
		a=read();
		stb[i][0][0]=stb[i][0][2]=-2e9;
		stb[i][0][1]=stb[i][0][3]=2e9;
		if(a>=0) stb[i][0][0]=stb[i][0][1]=a; 
		if(a<=0) stb[i][0][2]=stb[i][0][3]=a;
	}
	for(int i=2; i<=max(n, m); ++i) lo[i]=lo[i>>1]+1;
	for(int cs=1; cs<=lo[n]; ++cs) {
		for(int i=1; i+(1<<cs)-1<=n; ++i) {
			sta[i][cs][0]=max(sta[i][cs-1][0], sta[i+(1<<cs-1)][cs-1][0]);
			sta[i][cs][1]=min(sta[i][cs-1][1], sta[i+(1<<cs-1)][cs-1][1]);
			sta[i][cs][2]=max(sta[i][cs-1][2], sta[i+(1<<cs-1)][cs-1][2]);
			sta[i][cs][3]=min(sta[i][cs-1][3], sta[i+(1<<cs-1)][cs-1][3]);
		}
	}
	for(int cs=1; cs<=lo[m]; ++cs) {
		for(int i=1; i+(1<<cs)-1<=m; ++i) {
			stb[i][cs][0]=max(stb[i][cs-1][0], stb[i+(1<<cs-1)][cs-1][0]);
			stb[i][cs][1]=min(stb[i][cs-1][1], stb[i+(1<<cs-1)][cs-1][1]);
			stb[i][cs][2]=max(stb[i][cs-1][2], stb[i+(1<<cs-1)][cs-1][2]);
			stb[i][cs][3]=min(stb[i][cs-1][3], stb[i+(1<<cs-1)][cs-1][3]);
		}
	}
	while(q--) {
		int A[4], B[4];
		int l, r, cs;
		l=read(); r=read(); cs=lo[r-l+1];
		A[0]=max(sta[l][cs][0], sta[r-(1<<cs)+1][cs][0]); A[1]=min(sta[l][cs][1], sta[r-(1<<cs)+1][cs][1]);
		A[2]=max(sta[l][cs][2], sta[r-(1<<cs)+1][cs][2]); A[3]=min(sta[l][cs][3], sta[r-(1<<cs)+1][cs][3]);
		l=read(); r=read(); cs=lo[r-l+1];
		B[0]=max(stb[l][cs][0], stb[r-(1<<cs)+1][cs][0]); B[1]=min(stb[l][cs][1], stb[r-(1<<cs)+1][cs][1]);
		B[2]=max(stb[l][cs][2], stb[r-(1<<cs)+1][cs][2]); B[3]=min(stb[l][cs][3], stb[r-(1<<cs)+1][cs][3]);
		ll ans=-1e18, sum;
		for(int i=0; i<4; ++i) {
			if(abs(A[i])==2e9) continue ;
			sum=1e18;
			for(int j=0; j<4; ++j) {
				if(abs(B[j])==2e9) continue ;
				sum=min(sum, 1LL*A[i]*B[j]);
			}
			ans=max(ans, sum);
		}
		cout<<ans; putchar('\n');
	}
}

T3 星战( \(galaxy\) ) 2s 512M

其实把话说明白了,就是问你当前这个时候是不是所有点的入度都为 \(1\)
一个很奇怪的思路。
用一个数去表示是否当前每一个点的入度都是 \(1\),也就是哈希一下。
那么按照每一个点的编号的平方乘上出度个数的值的和去哈希。
先算出一个标准值,即入度都为 \(1\) 的时候,哈希值应该是什么。
然后开始维护哈希值就行了。

int n, m, q, t;
int u, v;
ll tmp[500005];
ll sy[500005];
ll Sum;
ll Rit;
int main(){
	n=read(); m=read();
	for(int i=1; i<=n; ++i) Rit+=i*i;
	for(int i=1; i<=m; ++i) {
		u=read(); v=read();
		sy[v]+=u*u;
		tmp[v]+=u*u;
		Sum+=u*u;
	}
	q=read();
	while(q--) {
		t=read();
		if(t==1) {
			u=read(); v=read();
			sy[v]-=u*u;
			Sum-=u*u;
		}
		if(t==2) {
			u=read();
			Sum-=sy[u];
			sy[u]=0;
		}
		if(t==3) {
			u=read(); v=read();
			sy[v]+=u*u;
			Sum+=u*u;
		}
		if(t==4) {
			u=read();
			Sum+=tmp[u]-sy[u];
			sy[u]=tmp[u];
		}
		if(Sum==Rit) puts("YES");
		else puts("NO");
	}
}

T4 数据传输( \(transmit\) ) 3s 1G

这道题没做出来,挺难的,只拿到了 \(52\) 分。
对于 \(k=1\) 的情况,路径权值和板子。
前面千量级的范围,直接 Dij 跑个最短路就行了。
建边的时候稍微有点特别,但是很好想。

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
using namespace std;
ll read(){
	ll x=0;bool f=1;char c=getchar();
	while(c>'9'||c<'0'){if(c=='-')f=0;c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
	return f?x:(~x)+1;
}
const ll maxn=200001;
ll n,m,q,k,rt,u,v,opt,x,y,z,ans;
ll far[maxn],dep[maxn],son[maxn],siz[maxn];
ll seg[maxn],rel[maxn],top[maxn],num[maxn];
struct EDGE{
	ll t,n;
}e[maxn<<1];
ll head[maxn],head_size;
struct tree{
	ll l,r;
	ll sum,lzy;
}t[maxn<<2];
void ADD(ll f,ll t){
	e[++head_size].t=t;
	e[head_size].n=head[f];
	head[f]=head_size;
}
//--------------------------------------------------------dfs预处理 
void dfs1(ll x,ll fa){
	++siz[x];dep[x]=dep[fa]+1;far[x]=fa;
	for(ll i=head[x];i;i=e[i].n){
		if(e[i].t==fa)continue;
		dfs1(e[i].t,x);
		siz[x]+=siz[e[i].t];
		if(siz[e[i].t]>=siz[son[x]])
		son[x]=e[i].t;
	}
}
void dfs2(ll x,ll fa){
	if(son[x]){
		int v=son[x];
		seg[v]=++seg[0];
		rel[seg[0]]=v;
		top[v]=top[x];
		dfs2(v,x);
	}
	for(ll i=head[x];i;i=e[i].n){
		if(top[e[i].t])continue ;
		int v=e[i].t;
		seg[v]=++seg[0];
		rel[seg[0]]=v;
		top[v]=v;
		dfs2(v,x);
	}
}
//--------------------------------------------------------线段树
void pushup(ll g){t[g].sum=t[g<<1].sum+t[g<<1|1].sum;}
void build(ll l,ll r,ll g){
	if(l==r){
		t[g].l=t[g].r=l;
		t[g].sum=num[rel[l]];
		return ;
	}
	ll mid=l+r>>1;
	build(l,mid,g<<1);build(mid+1,r,g<<1|1);
	t[g].l=l;t[g].r=r;
	pushup(g);
}
ll SUM(ll g,ll x,ll y){
	if(x<=t[g].l&&t[g].r<=y){
		return t[g].sum;
	}
	ll mid=t[g].l+t[g].r>>1;ll re=0;
	if(x<=mid)re+=SUM(g<<1,x,y);
	if(y>mid)re+=SUM(g<<1|1,x,y);
	return re;
}
ll LCASUM(ll x,ll y){
	ll fx=top[x],fy=top[y];
	ll re=0;
	while(fx!=fy){
		if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
		re+=SUM(1,seg[fx],seg[x]);
		x=far[fx];fx=top[x];
	}
	if(dep[x]>dep[y])swap(x,y);
	re+=SUM(1,seg[x],seg[y]);
	return re;
}
ll dis[5003][5003];
int pd[5003][5003];
struct edge{
	int t, n;ll d;
}E[8000006];
int head2[200005], head_size2;
void add(int f, int t, ll d) {
	E[++head_size2]=(edge) {t, head2[f], d};
	head2[f]=head_size2;
}
struct node {
	int v; ll diss;
	bool operator < (const node &a) const {
		return a.diss<diss;
	}
};
priority_queue<node>Q;
void DFS(int x, int fa, int now, int dep) {
	if(x!=now) add(now, x, num[x]);
	if(dep==k) return ;
	for(int i=head[x]; i; i=e[i].n) {
		if(e[i].t==fa) continue ;
		DFS(e[i].t, x, now, dep+1);
	}
}
void jianbian() {
	for(int i=1; i<=n; ++i) DFS(i, i, i, 0);
}
void Dij(int S) {
	dis[S][S]=0;
	Q.push((node){S, 0});
	while(!Q.empty()) {
		node op=Q.top(); Q.pop();
		if(op.diss>dis[S][op.v]) continue ;
		for(int i=head2[op.v]; i; i=E[i].n) {
			if(dis[S][E[i].t]>dis[S][op.v]+E[i].d) {
				dis[S][E[i].t]=dis[S][op.v]+E[i].d;
				Q.push((node){E[i].t, dis[S][E[i].t]});
			}
		}
	}
}
int main(){
	n=read(); q=read(); k=read(); rt=1;
	for(ll i=1;i<=n;i++){
		num[i]=read();
	}
	for(ll i=1;i<n;i++){
		u=read();v=read();
		ADD(u,v);ADD(v,u);
	}
	if(k==1) {
		top[rt]=rt;seg[rt]=++seg[0];rel[seg[0]]=rt;
		dfs1(rt,rt); dfs2(rt,rt); build(1,n,1);
	}
	if(k!=1) {
		jianbian();
		memset(dis, 0x3f, sizeof(dis));
		for(int i=1; i<=n; ++i) Dij(i);
	}
	while(q--) {
		u=read(); v=read();
		if(k==1) {
			cout<<LCASUM(u, v); putchar('\n');
		}
		else {
			cout<<num[u]+dis[u][v];
			putchar('\n');
		}
	}
}

NOIP 也这个水平就好了。

posted @ 2022-11-02 17:57  Konnya_ku  阅读(82)  评论(0编辑  收藏  举报