首页 > 其他分享 >ABC #267 C、D、E、F

ABC #267 C、D、E、F

时间:2022-09-07 15:58:19浏览次数:103  
标签:ABC idx int ll long 267 dfs top

C - Index × A(Continuous ver.) (atcoder.jp)

考虑维护一个长度为m的滑动窗口,滑动窗口从左往右移动的过程中,维护\(\sum_{i=1}^Mi*B_i\)。

  1. 右端点往后移动一格到位置i,对应res+=m*a[i]
  2. 左端点往后移动一格到位置i,由于窗口中每个位置的编号都会减少1,所以需要减去的是一段连续和,假设s[i]=sum(a[1] to a[i]),则右移一格对应res-=s[r]-s[i-2]
const int N=2e5+5;
typedef long long ll;
int n,m;
int a[N];
ll s[N];
ll res;

void del(int l,int r){
	res-=s[r]-s[l-1];
}

void add(int p,int k){
	res+=(ll)a[p]*k;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
		s[i]=s[i-1]+a[i];
	}
	
	ll ans=-1e18;
	for(int l=1,r=0;l<=n;del(l,r),l++){
		while(r-l+1<m && r<n){
			r++;
			add(r,r-l+1);
		}
		if(r-l+1==m)ans=max(ans,res);
	}
	
	cout<<ans<<endl;
	
	return 0;
}

D - Index × A(Not Continuous ver.) (atcoder.jp)

学魔怔了,想了一个\(O(N^3)\)的dp,在那优化了半天优化到\(O(N^2)\)。

当时dp的定义是:f[i][j]:前i个数中选择j个数并且选了i的所有方案,朴素的转移方程就是f[i][j]=max(f[t][j-1]+j*a[i]),t<i。然后发现dp过程中可以同时求出f[t][j-1]中的最大值,优化掉了一维。

const int N=2005;
typedef long long ll;
ll f[N][N];
ll g[N][N];
int n,m;
int a[N];

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	
	memset(f,-0x3f,sizeof(f)); memset(g,-0x3f,sizeof(g));
	f[0][0]=0;
	for(int i=0;i<=n;i++)g[i][0]=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m && j<=i;j++)g[i][j]=g[i-1][j];
		
		for(int j=1;j<=m && j<=i;j++){
			f[i][j]=max(f[i][j],g[i-1][j-1]+(ll)j*a[i]);
			g[i][j]=max(g[i][j],f[i][j]);
		}
	}
	
	ll ans=-1e18;
	for(int i=m;i<=n;i++)ans=max(ans,f[i][m]);
	cout<<ans<<endl;
	return 0;
}

其实可以直接定义:f[i][j]:前i个数中选择j个数的所有方案,转移的时候看a[i]选或者不选。实现的时候可以把第一位滚动掉。

typedef long long ll;
const int N=2005;
ll f[N];
int n,m;
int a[N];

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	
	memset(f,-0x3f,sizeof(f));
	f[0]=0;
	for(int i=1;i<=n;i++){
		for(int j=m;j>=1;j--){
			f[j]=max(f[j],f[j-1]+(ll)j*a[i]);
		}
	}

	cout<<f[m]<<endl;
	return 0;
}

E - Erasing Vertices 2 (atcoder.jp)

二分答案。

首先,可以预处理出删除每个点需要的代价s[i]

二分删除所有点过程中的最大代价,我们需要将这个代价最小化,考虑如何写check函数。

假设二分的最大代价是mid

  1. 一开始,可以把所有s[i]<=mid的点都加入到栈中,并且打上标记,表示这些是可以删除的点。
  2. 每次从栈顶取出一个点,把它删去,注意到删去一个点只会影响到它周边点的s[i]值,我们只需要暴力维护一下周边点的s[i]即可。
  3. 维护周边点的s[i]的时候,如果该点不在栈中且s[i]<=mid,就把它加入栈中;如果该点在栈中,由于它的s[i]是单调减少的,所以无妨。
  4. 最后看是否所有点都打上了标记即可。
typedef long long ll;
const int N=2e5+5,M=2*N;
int n,m;
int a[N];
ll s[N],f[N];
int e[M],ne[M];
int h[N],idx;
int stk[N],vis[N],top;

void adde(int x,int y){
	e[idx]=y; ne[idx]=h[x]; h[x]=idx++;
}

bool check(ll gap){
	top=0;
	memcpy(f,s,sizeof(f));
	memset(vis,0,sizeof(vis));
	for(int i=1;i<=n;i++)
	 	if(f[i]<=gap){
	 		stk[++top]=i;
	 		vis[i]=1;
	 	}
	 	
	while(top){
		int u=stk[top--];
		for(int i=h[u];~i;i=ne[i]){
			int v=e[i];
			f[v]-=a[u];
			if(f[v]<=gap && !vis[v]){
				stk[++top]=v;
				vis[v]=1;
			}
		}
	}
	
	for(int i=1;i<=n;i++)
		if(!vis[i])return 0;
		
	return 1;
}

int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	
	int x,y;
	memset(h,-1,sizeof(h));
	for(int i=1;i<=m;i++){
		scanf("%d%d",&x,&y);
		adde(x,y); adde(y,x);
	}
	
	for(int i=1;i<=n;i++){
		for(int j=h[i];~j;j=ne[j]){
			int v=e[j];
			s[i]+=a[v];
		}
	}
	
	ll l=0,r=2e14+1;
	while(l<r){
		ll mid=(l+r)>>1;
		if(check(mid))r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
	return 0;
}

F - Exactly K Steps (atcoder.jp)

树的直径,k级祖先。

根据树的直径的性质,我们可以知道距离树上任意一点u最远的点一定是直径的端点,因此问题就转化成了:从直径的其中一个端点为根,找到u的k级祖先。

直径的两个端点可以用两遍dfs求出。

k级祖先考虑用栈+离线+dfs的方法来求:用栈维护当前dfs从跟到u的路径上的点,可以知道如果u存在k级祖先,stack[top-k]就是满足条件的一个。

const int N=2e5+5,M=2*N;
int n,q;
int e[M],ne[M];
int h[N],idx;
int d1,d2,ma;
int dep[N];
struct que{
	int x,k;
}qz[N];
vector<int>w[N],ans[N];
int stk[N],top;

void adde(int x,int y){
	e[idx]=y; ne[idx]=h[x]; h[x]=idx++;
}

void dfs_far(int u,int fa,int &d){
	dep[u]=dep[fa]+1;
	if(dep[u]>ma){
		d=u; ma=dep[u];
	}
	
	for(int i=h[u];~i;i=ne[i]){
		int v=e[i];
		if(v==fa)continue;
		dfs_far(v,u,d);
	}
}

void dfs_anc(int u,int fa){
	stk[++top]=u;
	for(int i=0;i<w[u].size();i++){
		int k=w[u][i];
		if(top>k)ans[u][i]=stk[top-k];
	}

	for(int i=h[u];~i;i=ne[i]){
		int v=e[i];
		if(v==fa)continue;
		dfs_anc(v,u);
	}
	
	top--;
}

int main(){
	scanf("%d",&n);
	int x,y;
	memset(h,-1,sizeof(h));
	for(int i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		adde(x,y); adde(y,x);
	}
	
	dfs_far(1,0,d1);
	memset(dep,0,sizeof(dep)); ma=0;
	dfs_far(d1,0,d2);
	
	scanf("%d",&q);
	for(int i=1;i<=q;i++){
		scanf("%d%d",&x,&y);
		w[x].push_back(y);
		qz[i]={x,(int)w[x].size()-1};
	}
	for(int i=1;i<=n;i++)ans[i].resize((int)w[i].size());
	
	dfs_anc(d1,0);
	dfs_anc(d2,0);

	for(int i=1;i<=q;i++){
		int val=ans[qz[i].x][qz[i].k];
		if(!val)printf("%d\n",-1);
		else printf("%d\n",val);
	}
	
	return 0;
}

标签:ABC,idx,int,ll,long,267,dfs,top
From: https://www.cnblogs.com/tshaaa/p/16665725.html

相关文章

  • AtCoder Beginner Contest 267
    A-Saturday题意:给定今天的日期,问到周六还有几天。分析:暴力判断即可。代码:intmain(){ cin>>s; if(s=="Monday")ans=5; if(s=="Tuesday")ans=4; if(s=="We......
  • AtCoder Beginner Contest 267
    https://atcoder.jp/contests/abc267全部的AC代码:https://atcoder.jp/contests/abc267/submissions/me?f.Task=&f.LanguageName=&f.Status=AC&f.User=HinanawiTenshiE......
  • 三个稠密矩阵A,B,C的乘积ABC,假设三个矩阵的尺寸分别为mn,np,pq,且m<n<p<q,以下计算顺序
    题目在深度学习中,涉及到大量矩阵相乘,现在需要计算三个稠密矩阵A,B,C的乘积ABC,假设三个矩阵的尺寸分别为mn,np,p*q,且m<n<p<q,以下计算顺序效率最高的是:()a.A(BC)b.(AB)C......
  • ABC261
    IntersectionTournamentResultNewFolder(1)FlippingandBonusManyOperationsSortingColorBallsReplaceGameonGraph......
  • ABC265 F - Manhattan Cafe
    前缀和优化DPF-ManhattanCafe(atcoder.jp)题意给定n,d(n<=100,d<=1000)在n维空间中,给定两个点p,q,求点r的数量,满足r与p,q的曼哈顿距离均<=d思路首......
  • AtCoder Beginner Contest 267 解题报告
    A-Saturday题意:输入字符串代表周一至周五的某一天,输出这一天离周六还有多少天分析:映射一下,直接输入输出ac代码:#include<iostream>#include<algorithm>#inclu......
  • AtCoder Beginner Contest 267
    E-ErasingVertices2做法1观察可得:对于某个时刻,贪心删当前代价最小的点肯定是最优的。但是删一个点会减少相邻接的点的代价。然后就想到了堆,但是这个堆需要支持decre......
  • AtCoder Beginner Contest 267 E Erasing Vertices 2
    ErasingVertices2二分||贪心二分的做法就二分答案,然后检查一下能否删除,像拓扑一下跑一下就行#include<iostream>#include<cstdio>#include<algorithm>#includ......
  • ABC267总结
    比赛链接比赛情况AC:6/8题目分析A(语法入门)打表周一到周五即可B(基础算法)按照题意计算即可假如1号球没倒,则非法否则分别找最左和最右分别没倒的列,判断中间是否有一......
  • ABC法、蒙特卡罗法,帕累托法
    ABC,activitybasedcosting基于活动的成本计算法,主要用于对现有流程的描述和成本分析。与价值链分析法类似,将现有的业务进行分解,找出基本活动。基于活动成本分析法着重分......