【比赛记录】2025CSP-S模拟赛14

A B C D Sum Rank
50 17 - 20 87 5/21

A. 魔力屏障

区间 DP,设 \(f_{l,r,x}\) 表示击破 \([l,r]\),向右传递 \(x\) 的最小花费。转移分为先击破右区间再击破左区间、用左区间的剩余击破右区间两种。(第二个转移可以简化为用 \([l,r-1]\) 击破 \(r\)。)

(区间 DP)带有 \(\frac{1}{8}\) 的小常数。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
int n,a[75],f[75][75][155];
il void upd(int &x,int y){
	x=min(x,y);
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=n;i++){
		cin>>a[i];
		f[i][i][a[i]>>1]=a[i];
	}
	for(int len=2;len<=n;len++){
		for(int l=1,r=len;r<=n;l++,r++){
			/*bb*/
			for(int x=a[r]>>1;x<=150;x++){
				for(int i=l;i<r;i++){
					for(int y=a[i]>>1;y<=150;y++){
						upd(f[l][r][x],f[l][i][y]+f[i+1][r][x-y]);
					}
				}
			}
			for(int x=a[r-1]>>1;x<=150;x++){
				upd(f[l][r][max(x,a[r])>>1],f[l][r-1][x]+max(a[r]-x,0));
			}
		}
	}
	for(int i=1;i<=n;i++){
		cout<<*min_element(f[1][i],f[1][i]+151)<<" ";
	}
	return 0;
}
}
int main(){return asbt::main();}

B. 诡秘之主

C. 博弈

首先强制 \(T\) 为根。设 \(f_u\) 表示在 \(u\) 的子树中走下去再走上来的最小操作次数,通过树形 DP 可以求出。再设 \(g_u\) 表示从 \(u\) 走到根要剪掉的边。考虑二分答案,check 出能不能在 \(mid\) 的操作次数内使小 N 走到根即可。具体方式为删去若进入则必定超过 \(mid\) 的子树,考察此时的操作次数是否够用。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
namespace IO{
	const int bufsz=1<<20;
	char ibuf[bufsz],*p1=ibuf,*p2=ibuf;
	#define getchar() (p1==p2&&(p2=(p1=ibuf)+fread(ibuf,1,bufsz,stdin),p1==p2)?EOF:*p1++)
	il int read(){
		char ch=getchar();
		while(ch<'0'||ch>'9'){
			ch=getchar();
		}
		int x=0;
		while(ch>='0'&&ch<='9'){
			x=(x<<1)+(x<<3)+(ch^48);
			ch=getchar();
		}
		return x;
	}
	#undef getchar
}
using IO::read;
const int maxn=1e6+5;
int n,T,S,f[maxn],g[maxn],deg[maxn],fa[maxn];
vector<int> e[maxn]; 
il void dfs(int u){
	int hp[5]={0};
	int son=deg[u]-(fa[u]?1:0);
	if(fa[u]){
		g[u]+=son-1;
	}
	for(int v:e[u]){
		if(v==fa[u]){
			continue;
		}
		fa[v]=u;
		g[v]=g[u];
		dfs(v);
		hp[3]=f[v];
		sort(hp+1,hp+4,greater<int>());
	}
	if(!son){
		f[u]=0;
	}
	else if(son==1){
		f[u]=1;
	}
	else{
		f[u]=hp[2]+son;
	}
}
il bool check(int x){
	int u=S,las=-1,res=0,cnt=1;
	while(u!=T){
		int lar=res;
		for(int v:e[u]){
			if(v!=fa[u]&&v!=las&&f[v]+g[u]+lar+(las==-1)>x){
				res++;
			}
		}
		if(res>cnt||res>x){
			return 0;
		}
		las=u,u=fa[u],cnt++;
	}
	return 1;
}
int main(){
	n=read(),T=read(),S=read();
//	cout<<n<<T<<S<<"\n";
	for(int i=1,u,v;i<n;i++){
		u=read(),v=read();
//		cout<<u<<" "<<v<<"\n";
		e[u].pb(v),e[v].pb(u);
		deg[u]++,deg[v]++;
	}
	dfs(T);
//	for(int i=1;i<=n;i++){
//		cout<<f[i]<<" "<<g[i]<<"\n";
//	}
	int l=0,r=n;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid)){
			r=mid;
		}
		else{
			l=mid+1;
		}
	}
	cout<<l;
	return 0;
}
}
int main(){return asbt::main();}

D. 地雷

\(f_{l,r,x,y}\) 表示 \([l,r]\) 删完时 \(l-1\)\(r+1\) 都没有删,\(x\) 左侧的都比 \(x\) 删的早,\(y\)\(r+1\) 右侧第一个没有删的位置的最大代价。

于是有转移:

\[f_{l,r,x,y}=\max\{f_{l,i-1,x,k}+cost(l-1,i,r+1,y)+f_{i+1,r,k,y}\} \]

代码具体实现细节多的要死。

复杂度 \(O(n^6)\),但常数非常小,可以通过。

实测只会转移 2e8 次。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
int n,p[75],q[75],r[75],s[75],f[75][75][75][75];
il int sq(int x){
	return x*x;
}
il int calc(int a,int b,int c,int d){
	return sq(p[a]-q[b])+sq(p[b]-r[c])+sq(p[c]-s[d]);
}
il void upd(int &x,int y){
	x=x<y?y:x;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>p[i];
	}
	for(int i=1;i<=n;i++){
		cin>>q[i];
	}
	for(int i=1;i<=n;i++){
		cin>>r[i];
	}
	for(int i=1;i<=n;i++){
		cin>>s[i];
	}
	memset(f,-0x3f,sizeof(f));
	for(int i=1;i<=n+1;i++){
		f[i][i-1][i-1][i]=0;
		for(int j=i+1;j<=n+1;j++){
			f[i][i][i][j]=f[i][i][i-1][j]=calc(i-1,i,i+1,j);
			f[i][i-1][i-1][j]=0;
		}
	}
	for(int len=2;len<=n;len++){
		for(int l=1,r=len;r<=n;l++,r++){
			for(int x=l-1;x<=r;x++){
				for(int y=r+1;y<=n+1;y++){
					int &res=f[l][r][x][y];
					for(int i=max(x,l);i<=r;i++){
						int j=i==x?l-1:x,tmp=calc(l-1,i,r+1,y);
						upd(res,f[l][i-1][j][r+1]+tmp+f[i+1][r][i][y]);
						for(int k=i+1;k<=r;k++){
							upd(res,f[l][i-1][j][k]+tmp+f[i+1][r][k][y]);
						}
					}
				}
			}
		}
	}
	cout<<f[1][n][0][n+1];
	return 0;
}
}
int main(){return asbt::main();}
posted @ 2025-07-10 14:08  zhangxy__hp  阅读(38)  评论(1)    收藏  举报