2024暑假集训测试10

前言

image

这回挂的比较少,就 T2 唐了太长时间导致 T4 暴力没打完挂了 \(60\),不过 T4 暴力给的非常多,但也并不好打,T3 赛后因数据水安排重测,重测后还往上涨了 \(2\) 名,因为我的解法就是本着 \(60pts\) 部分分去的,没有卡掉我。

T1 花间叔祖

考虑另 \(P=2\)\(ans\) 最大为 \(2\),故只有 \(ans=1\) 时才更优,即所有数 \(\bmod P\) 均同余。

将数组排序,求每相邻两个 \(a_i\) 的差的 \(\gcd\),若最终结果 \(\ne 1\)\(ans=1\)

T2 合并 r

  • 原题

  • 部分分 \(10pts\):爆搜即可。

  • 正解:

    挺巧妙的一个 DP,感觉赛时不打表大概率想不出来。

    定义 \(f_{i,j}\) 表示处理到第 \(i\) 位,当前和为 \(j\) 的方案数,发现若 \(j\) 能被拼出来,则 \(\dfrac{j}{2}\) 也一定能被拼出来,直接全部 \(÷2\) 即可;同样的 \(j+1\) 也一定能被拼出来。

    如此只枚举整数的 \(j\),按上述方式转移,即可不重不漏统计答案,有:

    \[f_{i,j}=f_{i-1,j-1}+f_{i,j\times 2} \]

    第一反应会对正确性提出疑问,但是首先因为和为整数,故最后结果为小数的没有任何贡献;\(+1\)\(÷2\) 的前后顺序出来的方案也是不同的,满足了不漏。发现后 \(÷2\) 的一定比先 \(÷2\) 的大,也满足了从小到大排序,做到了不重。

    初始值 \(f_{1,1}=1\),答案为 \(f_{n,k}\)

T3 回收波特

  • 原题

  • 部分分,理论 \(30pts\):对于特殊性质 \(1\) 直接 \(O(nm)\) 跑,但好像数据水还能多拿点?

  • 部分分,理论 \(60pts\):对于特殊性质 \(2\),值域很小,存在大量重合的点,所有重合的点只处理一个即可。

  • 正解:

    很巧妙的一个做法,发现对于 \(a_i=-a_j\),即两点关于原点对称,则后面的操作其都对称,只处理一个即可。

    随后利用移动原点的方法,发现之前原点两边都有不能移动原点,但现在可以了;对于全在 \(tag\) 右边的 \(tag\) 右移 \(d\),反之左移 \(d\),若仍全在其一边无需操作,否则将小的一边合并到大的一边,直接连边即可。

    发现这样的话点的位置从来没动过,所以若无法回收的话其最后的位置就是 \(i-dag\),让后跑 \(dfs\) 将对称的那些处理掉就可以了。

    因为值域上每个点最多被处理一次,复杂度 \(O(n+m)\)

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long 
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=1e6+10;
    const double eps=1e-8;
    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,l=N-10,r,mid,maxx,tag,stop[N],pos[N],a[N];
    bool vis[N];
    vector<int>e[N];
    void dfs(int x)
    {
        if(vis[x]) return ;
        vis[x]=1;
        for(int y:e[x])
        {
            if(stop[x]) stop[y]=stop[x];
            else pos[y]=-pos[x];
            dfs(y);
        }
    }
    signed main()
    {
        read(n),read(m);
        for(int i=1;i<=n;i++) 
        {
            read(a[i]);
            l=min(l,a[i]);
            r=max(r,a[i]);
            maxx=r;
        }
        for(int i=1,d;i<=m;i++)
        {
            read(d);
            if(l+tag>0) tag-=d;
            else tag+=d;
            mid=-tag;
            if(l<=mid&&r>=mid)
            {
                stop[mid]=i;
                if(mid-l<=r-mid)
                {
                    for(int j=l;j<=mid-1;j++)
                        e[mid*2-j].push_back(j);
                    l=mid+1;
                }
                else
                {
                    for(int j=mid+1;j<=r;j++)
                        e[mid*2-j].push_back(j);
                    r=mid-1;
                }
            }
        }
        for(int i=l;i<=r;i++)
        {
            if(!stop[i]) pos[i]=i+tag;
            dfs(i);
        }
        for(int i=1;i<=l-1;i++)
            if(stop[i]) dfs(i);
        for(int i=r+1;i<=maxx;i++)
            if(stop[i]) dfs(i);
        for(int i=1;i<=n;i++)
        {
            if(stop[a[i]]) printf("Yes %d\n",stop[a[i]]);
            else printf("No %d\n",pos[a[i]]);
        }
    }
    

T4 斗篷

  • 部分分 \(65pts\)

    对于每个 x 以他为右下角的点,其向左最多扩展 \(l\),向上最多扩展 \(u\),那么对于每个其向左能扩展到的点向下最多扩展 \(d\),若 \(d>\min(l,u)\) 则产生贡献。暴力预处理然后枚举,复杂度是 \(O(n^3)\) 的。

  • 正解:

    考虑怎么优化,依然是处理出每个点的 \(l,u,d\),类似于二维偏序的,每个 \(x\) 都能对 \(x+1\sim x+d_x\) 产生贡献,故处理两个二维偏序分别表示询问和修改处理即可,将代码打出来就会感觉挺好理解的。

    点击查看代码
    #include<bits/stdc++.h>
    #define ll long long 
    #define endl '\n'
    #define sort stable_sort
    using namespace std;
    const int N=1.2e4+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,cs,qs;
    ll ans;
    short f[3][N>>1][N];
    char s[N>>1][N];
    struct bb
    {
        ll c[N];
        int lowbit(int x) {return x&-x;}
        void change(int x) {for(;x<=cs;x+=lowbit(x)) c[x]++;}
        int ask(int l,int r)
        {
            l--;
            ll ans=0;
            for(;r;r-=lowbit(r)) ans+=c[r];
            for(;l;l-=lowbit(l)) ans-=c[l];
            return ans;
        }
        void clear() {memset(c,0,cs*sizeof(ll));}
    }t;
    struct aa {int l,r,val;}q[N],c[N];
    bool cmp(aa a,aa b) {return a.val<b.val;}
    void calc(int s,short *l,short *u,short *d)
    {
        cs=0,qs=0;
        for(int i=s;i<=m;i+=4)
        {
            cs++;
            if(i!=s&&l[i]&&u[i]) q[++qs]={cs-min(l[i],u[i]),cs-1,cs};
            c[cs]={cs,cs,d[i]+cs};
        }
        sort(c+1,c+1+cs,cmp),sort(q+1,q+1+qs,cmp);
        t.clear();
        int j=cs;
        for(int i=qs;i>=1;i--)
        {
            for(;j>=1&&c[j].val>=q[i].val;j--) t.change(c[j].l);
            ans+=t.ask(q[i].l,q[i].r);
        }
    }
    signed main()
    {
        read(n),read(m);
        n=(n<<1)-1;
        m=(m<<1)-1;
        char ch=getchar();
        for(int i=1;i<=n;i++)
        {
            for(;ch=='\n'||ch=='\r';ch=getchar());
            for(int j=1;j<=m&&ch!='\n'&&ch!='\r';j++,ch=getchar())
                s[i][j]=ch;
        }
        for(int i=1;i<=n;i+=2)
            for(int j=i%4;j<=m;j+=4)
            {
                if(j>=4&&s[i][j-1]=='-') f[0][i][j]=f[0][i][j-4]+1;
                if(i>1&&j>1&&s[i-1][j-1]=='\\') f[1][i][j]=f[1][i-2][j-2]+1;
                if(i>1&&j<m&&s[i-1][j+1]=='/') f[2][i][j]=f[2][i-2][j+2]+1;
            }
        for(int i=3;i<=n;i+=2)
            calc(i%4,f[0][i],f[1][i],f[2][i]);
        memset(f[1],0,sizeof(f[1]));
        memset(f[2],0,sizeof(f[2]));
        for(int i=n-2;i>=1;i-=2)
            for(int j=i%4;j<=m;j+=4)
            {
                if(j>1&&s[i+1][j-1]=='/') f[1][i][j]=f[1][i+2][j-2]+1;
                if(j<m&&s[i+1][j+1]=='\\') f[2][i][j]=f[2][i+2][j+2]+1;
            }
        for(int i=1;i<=n-1;i+=2)
            calc(i%4,f[0][i],f[1][i],f[2][i]);
        write(ans);
    }
    

总结

T4 输入比较抽象,fgets OJ 过不去 luogu 能过,一个一个 getchar OJ 能过 luogu 过不去,比较抽象。

T4 挺麻烦的其实,但最近学长和教练好像有意鼓励我们坚持调麻烦的题与暴力,可见这次暴力给的非常多,\(rank1\) 更是一道题没 A,学长说 T4 现在不调以后早晚还会碰到类似解法,所以唐了将近一上午也是给调了。

讲题的时候学长教了对拍,于是学了一下。

posted @ 2024-07-24 21:31  卡布叻_周深  阅读(22)  评论(0编辑  收藏  举报