abc318
abc318
总评:智障了好多次,不过这种智障的修改感觉很有意义,因为平常考试我也会扔掉简单的去写麻烦的
D
发现 \(n\le 16\) 因为我们最多选 \(n/2\) 条边,所以只会最多选出来 \(8\) 条边,直接 dfs 找每个点选哪条边即可
要注意可以不选某条边
E
首先考虑对于两个颜色相同的点 \(i,j\) ,他们会产生的贡献是 \(i,j\) 之间的距离减去中间和 \(i,j\) 一样颜色的个数
设 \(v_i\) 表示某个颜色的第 \(i\) 个所在原序列的位置,那么 \(i,j\) 的贡献就是 \((v_j-v_i-1)-(j-i-1)\)
发现可以把 \(i\) 和 \(j\) 的贡献拆开,那也就是 \(v_j-j+i-v_i\)
也就是说 \(i\) 后面的每一个 \(j\) 都能给 \(i\) 提供 \(i-v_i\) 的贡献,\(j\) 前面的每一个 \(i\) 都可以给 \(j\) 提供 \(v_j-j\) 的贡献
用个 \(vector\) 记录每个颜色所在的位置即可
F
题意:
在一条数线上有一个章鱼形机器人和 \(N\)个宝物。第 \(i\) 个宝物 \((1\leq i\leq N)\) 位于坐标 \(X_i\) 处。
机器人有一个头和\(N\) 条腿, \(i\) 条腿 \((1\leq i\leq N)\) 的长度为\(L_i\)。
求机器人能抓住所有 \(N\) 个宝物的整数 \(k\) 的个数如下。
- 将头部置于坐标 \(k\) 处。
- 依次对 \(i=1,2,\ldots,N\) 重复以下步骤:如果在距离头部 \(L_i\)的距离内,即在满足 \(k-L_i\leq x\leq k+L_i\) 的坐标 \(x\)处,有一件宝物尚未被抓取,则选择其中一件宝物并抓取。
分析:
先考虑如果固定 \(k\) 怎么判断,直接贪心的从大到小排序 到 \(k\) 的距离和腿的距离,让其一一匹配即可
可以发现一个性质,如果 \(k\) 出现在 \([l,r]\) 中,前提是其中没有任何一条腿正好碰到某一个宝藏,(正好碰到的意思是这个宝藏到 \(k\) 的距离等于腿的长度) ,那么对于任意的 \(i,j\in[l,r]\) ,如果 \(i\) 作为 \(k\) 合法,那么 \(j\) 作为 \(k\) 也合法
接下来证明这个结论:如果 \(i\) 能触摸到宝藏 \(j\) ,那么不管 \(k\) 在 \([l,r]\) 的任意一个位置,\(i\) 都能触摸到 \(j\) (其实这个结论是可以打表打出来的/cf)
考虑反证:如果一个点合法,说明每一条腿的长度至少比和他匹配的宝藏的距离大于 \(1\) ,那么如果出现 \(i\) 不能摸到 \(j\) ,那么说明在左右移动的过程中,有一个 \(i\) 他摸不到宝藏了,从能到不能,那么一定有一个边界导致 \(i\) 刚好摸到 \(j\) ,与前提相反,所以不会出现这种情况
接下来直接钦定某一个宝藏是由那一条腿碰到的,这样会有 \(O(n^2)\) 个 \(k\) ,把他们分成了 \(O(n^2)\) 段区间
只要在每一段随便选一个数判断合不合法即可,复杂度 \(O(n^3logn)\) 可过
代码:
int n,x[N],l[N];
int a[N],v[N],cnt;
bool check(int k){
FOR(i,1,n) a[i]=abs(k-x[i]);
sort(a+1,a+n+1);
FOR(i,1,n){
if (a[i]>l[i]) return 0;
}
return 1;
}
signed main(){
scanf("%lld",&n);
FOR(i,1,n) scanf("%lld",&x[i]);
FOR(i,1,n) scanf("%lld",&l[i]);
FOR(i,1,n){
FOR(j,1,n){
int k=x[i]+l[j];
v[++cnt]=k;
k=x[i]-l[j];
v[++cnt]=k;
}
}
sort(v+1,v+cnt+1);sort(l+1,l+n+1);
cnt=unique(v+1,v+cnt+1)-v-1;
int ans=0;
FOR(i,1,cnt-1){
if (check(v[i]+1)) ans+=(v[i+1]-v[i]-1);
}
FOR(i,1,cnt) if (check(v[i])) ans++;
printf("%lld\n",ans);
return 0;
}
G
题目分析:
判断路径是否经过某个点,还是在图上的操作,显然想到圆方树。
直接建出圆方树,并在 \(A\) 到 \(C\) 路径上的圆点和方点连接的圆点中,若有 \(B\) 那就 \(Yes\)。
代码:
bool flag;
int n,m,A,B,C;
int fa[N],dep[N];
int dfn[N],low[N],cnt,stk[N],top,tot;
vector<int> G1[N],G2[N];
void add(int u,int v){
G2[u].p_b(v);
G2[v].p_b(u);
}
void tarjan(int u){
dfn[u]=low[u]=++cnt;
stk[++top]=u;
for (auto v:G1[u]){
if (!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
if (low[v]>=dfn[u]){
int y;add(++tot,u);
do{
y=stk[top--],add(tot,y);
}while(y!=v);
}
}
else low[u]=min(low[u],dfn[v]);
}
}
void dfs(int u,int fath){
fa[u]=fath;dep[u]=dep[fath]+1;
for (auto v:G2[u]){
if (v==fath) continue;
dfs(v,u);
}
}
void check(int u){
if (u<=n&&u==B) flag=1;
else{
for (auto v:G2[u]){
if (v==B) flag=1;
}
}
}
signed main(){
scanf("%d%d",&n,&m);tot=n;
scanf("%d%d%d",&A,&B,&C);
for (int i=1;i<=m;i++){
int u=read(),v=read();
G1[u].p_b(v);
G1[v].p_b(u);
}
tarjan(1);dfs(1,0);flag=0;
while(A!=C){
if (dep[A]<dep[C]) swap(A,C);
check(A);
A=fa[A];
}
check(A);
if (flag) puts("Yes");
else puts("No");
return 0;
}