2020-2021 ACM-ICPC, Asia Seoul Regional Contest 部分题目解答

传送门
https://codeforces.com/gym/102920

B

签到

C

题意:给出n个点,其中k个是特殊点,求有多少个点在特殊点两两连接的路径之间(特殊点自身也算)。
分析:简单的树形DP。
对于一个结点u,它被计入贡献当且仅当下面的条件中存在一条或多条满足:

  • 它的两棵子树上都有特殊点
  • 它的父节点有特殊点子节点有特殊点
  • 它本身是特殊点
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

const int N=1e5+5;
struct node{
	int to,next;
}e[N<<1];
int head[N],tot;
void add(int u,int v){e[tot].to=v;e[tot].next=head[u];head[u]=tot++;}

bool tag[N];
int n,k;
int ans=0;

int dfs(int u,int fa){
	 int res=0;
	 if(tag[u]) res++;
	 
	 int cnt=0;
	 for(int i=head[u];~i;i=e[i].next){
	 	int go=e[i].to;
	 	if(go==fa) continue;
	 	int w=dfs(go,u);
	 	if(w) cnt++;
	 	res+=w;
	 }
	 if(res && res<=k-1 || tag[u] || cnt>=2) ans++;
	 return res;
}

int main(){
	memset(head,-1,sizeof head);
	cin>>n>>k;
	FOR(i,1,n-1){
		int u,v,w; cin>>u>>v>>w;
		add(u,v); add(v,u);
	}	
	
	FOR(i,1,k){
		int u; cin>>u;
		tag[u]=1;
	}

	dfs(1,-1);
	
	cout<<ans<<endl;
	
    return 0;
}

E

分析:递推
从最后一项开始分析,可以知道,最后一项只可能是0,1,而最后一项为1时,就是题目中的computer出了错误,我们可以对这个错误进行修正,那么
需要修改的就是最后一项的前一项了。

如何进行修正呢?

修正意味着i与另一个数的胜负由它们的大小关系决定
首先,我们考察项i:
可知对于i,能够产生大小判断波动大只有i-1,i+1,故在这里只需考察i及i-1(因为i与i+1已经修正过了)(方便起见,我们将i比旁边的数记为,i比旁边的数记为
i的胜场可以是0,1
而胜场的差(f值)也可以是0,1

具体修正方案:

我们约定(x,y)意味着i的前后两次胜负情况,比如(0,1)的意思是有一次i胜了0场,有一次胜了1场

而i+1项为1时(即f[i+1]=1,同时我们知道这意味着i项已经胜了一场),对此进行分类讨论:

  • f[i]=1时,i的两次胜负情况可能为(0,1) 因此在修正之后变为(0,0)
  • f[i]=0时,i的两次胜负情况可能为(1,1) 因此在修正之后变为(1,0)
代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

const int N=1e6+5;
int f[N];
int n;

int main(){
	cin>>n;
	FOR(i,1,n) cin>>f[i];
	
	bool ok=1;
	DWN(i,n,1){
		if(f[i]>=2 || f[i]<0){
			ok=0;
			break;
		}
		
		if(f[i]==1) f[i-1]=(f[i-1]==0?1:f[i-1]-1);
	}
	
	if(ok && !f[1]) puts("YES");
	else puts("NO");
    return 0;
}

L

题意:给定一个数组,求 \(max((a[i]+a[j])(j-i))\)
分析:决策单调性分治

代码
#pragma GCC optimize("O3")
#include<bits/stdc++.h>
using namespace std;
#define SET0(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(int i=(a);i<=(b);i++)
#define DWN(i,a,b) for(int i=(a);i>=(b);i--)
#define INF 0x3f3f3f3f
typedef long long ll;

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*10+ch-'0';ch=getchar();}
    return x*f;
}

const int N=1e6+5;
ll a[N];
int n;

int A1[N],A2[N];
ll ans=-1;

ll cal(int p1,int p2){
	ll res=(A2[p2]-A1[p1])*(a[A2[p2]]+a[A1[p1]]);
	return res;	
}

void solve(int l1,int r1,int l2,int r2){
	if(l1>r1) return;
	int mid=l1+r1>>1;
	int pos=l2;
	FOR(i,l2+1,r2)
		if(cal(mid,pos)<cal(mid,i)) pos=i;
	ans=ans>cal(mid,pos)?ans:cal(mid,pos);
	solve(l1,mid-1,pos,r2); solve(mid+1,r1,l2,pos);
}

int main(){
	cin>>n;
	FOR(i,1,n) a[i]=read();
	
	int cnt1=0,cnt2=0;
	A1[++cnt1]=1; A2[++cnt2]=n;
	FOR(i,2,n)
		if(a[i]>a[A1[cnt1]]) A1[++cnt1]=i;
	DWN(i,n-1,1)
		if(a[i]>a[A2[cnt2]]) A2[++cnt2]=i;
	solve(1,cnt1,1,cnt2);
	
	cout<<ans<<endl;
	
    return 0;
}

/* 
加了快读 109 ms	15700 KB 
不加TLE orz
*/
posted @ 2021-02-25 16:49  HinanawiTenshi  阅读(345)  评论(0编辑  收藏  举报