2024暑假集训测试12

前言

image

T2 其实和货车运输这题差不多但是由于给定图为树的部分分都没想出来压根没想到重构树,感觉不太应该,思路还是不清晰,赛时没有拿到那个部分分的,因为拿到的都顺着推出正解了;T3 是道黑,赛时 \(A,B\) 循环输出能拿到 \(40\) 分,赛后重测了;T4 题都看不懂。

没挂分因为根本没什么能挂的(毕竟后面几道题都不会)。

因为 T3 除了 rk1 其他人都是样例的 \(10pts\),T4 又没什么人会,导致大量并列的。

T1

签到题,考虑 \(a,b\) 同时加两次 \(1\) 和各加一次 \(2\) 时等价的,奇奇,奇偶,偶偶分类讨论即可。

T2

先考虑形态为树的怎么做,因为两点路径唯一,以边的编号为边权,\(dis_{x,y}\) 表示 \(x\)\(y\) 路径上的边权最大值,有 \(ans=\max\limits_{i=l}^r\{dis_{i,i+1}\}\)

基本上想到这个正解就出来了,Kruskal 重构树即可,和 货车运输 这道题是类似的,使路径上最大值最小,从小到大排序,建虚点边权转点权,\(dis_{x,y}=w_{lca(x,y)}\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long 
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=4e5+10;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool z=true;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(z?x:~x+1);
}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,m,q,root,f[N],w[N],dis[N],mx[N][20];
int fa[N],son[N],dep[N],top[N],sz[N];
vector<int>e[N];
struct aa {int x,y,w;}g[N];
bool cmp(aa a,aa b) {return a.w<b.w;}
int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
void kru()
{
    sort(g+1,g+1+m,cmp);
    int cnt=0;
    for(int i=1;i<=m;i++)
    {
        int x=g[i].x,y=g[i].y,z=g[i].w;
        x=find(x),y=find(y);
        if(x==y) continue;
        cnt++;
        f[x]=f[y]=cnt+n;
        e[x].push_back(cnt+n),e[cnt+n].push_back(y);
        e[y].push_back(cnt+n),e[cnt+n].push_back(x);
        w[cnt+n]=z;
        if(cnt==n-1) break ;
    }
    root=cnt+n;
}
void dfs1(int x,int father)
{
    fa[x]=father,dep[x]=dep[father]+1,sz[x]=1;
    for(int y:e[x])
    {
        if(y==father) continue;
        dfs1(y,x);
        sz[x]+=sz[y];
        son[x]=sz[son[x]]<sz[y]?y:son[x];
    }
}
void dfs2(int x,int t)
{
    top[x]=t;
    if(!son[x]) return ;
    dfs2(son[x],t);
    for(int y:e[x]) if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
int lca(int x,int y)
{
    for(;top[x]!=top[y];x=fa[top[x]])
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
    return dep[x]<dep[y]?x:y;
}
void ST()
{
    for(int i=1;i<=n-1;i++) mx[i][0]=dis[i];
    for(int j=1;j<=log2(n);j++)
        for(int i=1;i+(1<<j)-1<=n;i++)
            mx[i][j]=max(mx[i][j-1],mx[i+(1<<(j-1))][j-1]);
}
int ask(int l,int r)
{
    int t=log2(r-l+1);
    return max(mx[l][t],mx[r-(1<<t)+1][t]);
}
signed main() 
{
    read(n),read(m),read(q);
    for(int i=1;i<=m+n;i++) f[i]=i;
    for(int i=1,x,y;i<=m;i++)
    {
        read(x),read(y);
        g[i]={x,y,i};
    }
    kru();
    dfs1(root,0),dfs2(root,root);
    for(int i=1;i<=n-1;i++) dis[i]=w[lca(i,i+1)];
    ST();
    for(int i=1,l,r;i<=q;i++)
    {
        read(l),read(r);
        if(l==r) puts("0");
        else write(ask(l,r-1)),puts("");
    }
}

T3

官方题解思路太抽象了,感觉这个办法好理解的多。

Bob 的目的是不让 Alice 拿到最优,发现在 Bob 拿走最优解 \(a_i\) 之后 Alice 的次优解就变成了和 \(a_i\) 最相近的那个,将 \(a_i\) 排序,次优解就是 \(a_{i-1}\)\(a_{i+1}\),感觉这是一个瓶颈,赛时没有想到,如果想到这个基本上打不出正解也能骗不少分。

因为 Alice 先手,枚举其第一个选择的数,之后就是 BobAlice 轮流取,此时变成 Bob 是先手,因为已经排好序了,所以 \(a_i\) 就是挨个取,分 Alice 取奇数项和 Alice 取偶数项两种。

因为 \(n\) 是偶数,所以最后会剩下一个,考虑枚举这个点,对于 \(i\) 作为结束位置,其前面奇偶不变,其后边奇偶反过来,可以前缀和维护,简单手摸一下就理解了。

因为此时 Bob 是先手,所以必须满足 Alice 取奇和取偶两种都合法才行;有因为最开始 Alice 是先手,所以存在一组合法即为 Alice 获胜。

复杂度 \(O(n^2)\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long 
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=4e5+10;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool z=true;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(z?x:~x+1);
}
template<typename Tp> inline void wt(Tp x)
{if(x>9)wt(x/10);putchar((x%10)+'0');}
template<typename Tp> inline void write(Tp x)
{if(x<0)putchar('-'),x=~x+1;wt(x);}
ll T,n,l,r,a[N],b[N],odd[N],even[N],tot;
bool flag;
signed main() 
{
    read(T);
    while(T--)
    {
        read(n),read(l),read(r);
        for(int i=1;i<=n;i++) read(a[i]);
        sort(a+1,a+1+n);
        flag=0;
        for(int i=1;i<=n;i++)
        {
            if(flag) break;
            if(a[i]>r) break;
            tot=0;
            for(int j=1;j<=n;j++) if(i!=j) b[++tot]=a[j];
            for(int j=1;j<=tot;j++) 
            {
                odd[j]=odd[j-1]+(j&1)*b[j];
                even[j]=even[j-1]+!(j&1)*b[j];
            }
            for(int j=1;j<=tot;j++)
            {
                ll ans1=a[i]+odd[j-1]+even[tot]-even[j],
                    ans2=a[i]+even[j-1]+odd[tot]-odd[j];
                if((ans1>=l&&ans1<=r)&&(ans2>=l&&ans2<=r))
                {
                    flag=1;
                    break;
                }
            }
        }
        puts(flag?"Alice":"Bob");
    }
}

T4

题面还没读懂,先搁着。

总结

思路还是不够清晰,赛后看了做法总是一种恍然大悟的感觉,还多时候都怀疑自己赛时为啥想不到。

发现赛时思路还是太混乱了,静不下来。回忆一下打的最好的一次是一个人在 \(1\) 机房打的,今天 rk1 也是在家打的,环境自然比学校更容易静下心。当然考场上和教室氛围更相近,所以要做的是不被外界干扰,沉下心。

还是太容易受外界影响了,可能和身体不太好有关?但是每次身体有点不舒服的时候打的都比较差,但是上午打的好处就是不会因为中午路上太热虚掉。一着急就出汗,越出汗越着急。

每次都只能打出普及组的水平真的不行。

附录

题目背景十分抽象,这也是前面不写题名的原因,除了 T4 都和题目没有任何联系。

明天模拟赛的前言里提到 AliceBob?感觉要搞人啊。接下来几次貌似前言都写得很有恐吓感。

今天 rk2 太多,出题人零食大减。

posted @ 2024-07-26 20:21  卡布叻_周深  阅读(82)  评论(0)    收藏  举报