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
*/