• Educational Codeforces Round 123 (Rated for Div. 2)思路分享


    Educational Codeforces Round 123 (Rated for Div. 2)

    本来这场的状态不太好,到后面磕不出来的时候有点瞌睡了,到最后竟然没有记rating....(本来还指望着通过这场掉一波分,这样就能报下一场的div2了,自我感觉div2现在还没有到拿捏的程度,E,F就没有当场做出来的时候....)

    A. Doors and Keys

    A题算是签到题吧,只需要判断钥匙与门的先后顺序即可。

    B. Anti-Fibonacci Permutation

    B题要求构造一个排列使得他为非斐波那契数列,要求构造出b个排列。
    首先想到的就是倒序,之后发现我们将1依次向左移即可。
    即:
    4 3 2 1.
    4 3 1 2
    4 1 3 2
    1 4 3 2
    因为除了1之外,其他的元素都是倒序,注定符合\(a_i+a_{i+1}>a_{i+2}\)

    C. Increase Subarray Sums

    我承认我被这个题卡了许久,将近50分钟左右....
    由于n是5000的缘故,所以我们完全可以枚举所有的区间去统计答案。可以发现对于某个\(f(k)\)而言,它的答案只可能由以下部分组成:
    1.什么都不选,即答案为0.
    2.选取区间长度恰好为k的区间,并将这个区间内的每个数都加上x。
    3.选取区间长度小于k的区间,并将这个区间内的每个数都加上x。
    4.选取区间长度大于k的区间,并将这个区间内的和增加kx.
    第一部分不用考虑,我们只需要在最后的时候和0比大小即可。第二部分考虑我们枚举所有的区间的时候就可以办到了。第三部分其实就是f(0),f(1),f(2),...,f(k-1)取最大值,其实也好维护。
    接下来就是第4部分了。我们令g(k)表示区间长度为k的区间的最大值。那么第四部分也好考虑就是max(g(k+1),g(k+2),...,g(n))+k
    x;
    在我们枚举所有区间的时候后一方面维护第二部分的值,一方面维护g的即可。
    但其实我们发现不用这么麻烦,我们完全可以正着做一次,倒着做一次dp即可。正着的不多解释,关于倒着的,考虑如果x的对应的最优区间长度为y的话,则x+1对应的长度也为y。因为sum(y)+kx>sum(z)+kx(z为x+1对应的最优区间长度).则对于f(x+1)的时候,显然存在sum(y)+(k+1)x>sum(z)+(k+1)x.我们完全可以只从x+1出转移即可。具体的可以参考代码:

    点击查看代码
    #include<bits/stdc++.h> 
    #define ll long long
    #define db double 
    using namespace std;
    const int N=5010;
    int n,T,m,a[N];
    ll b[N];
    int main()
    {
    //    freopen("1.in","r",stdin);
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i) scanf("%d",&a[i]);
            memset(b,0xef,sizeof(b));
            for(int l=1;l<=n;++l)
            {
                ll sum=0; 
                for(int r=l;r<=n;++r)
                {
                    sum+=a[r];
                    b[r-l+1]=max(b[r-l+1],sum+(r-l+1)*m);
                }
            }
            for(int i=1;i<=n;++i) b[i]=max(b[i],b[i-1]);
            for(int i=n;i>=0;--i) b[i]=max(b[i],b[i+1]-m);
            for(int i=0;i<=n;++i) printf("%lld ",max(b[i],0ll));
            puts("");
        }
        return 0;
    }
    

    D. Cross Coloring

    这个题其实想到的话真的也不难。
    每次涂颜色都会将一个行,一个列涂成同一个颜色。考虑每次操作我们都有k种选择,总的来说答案就是\(k^q\)。但是会有特殊的情况,即假设我在某次操作中,涂了1行1列,之后这些元素全部被其他颜色覆盖了,那我这次操作就没有任何意义了。所以我们只需要将这些操作删选出来即可。可以采用倒序的方法,记录下哪些行,列已经被涂过了,以及是否所有的行列都被涂过了。

    点击查看代码
    #include<bits/stdc++.h> 
    #define ll long long
    #define db double 
    using namespace std;
    const int N=2e5+10,P=998244353;
    int n,T,m,q,k,vish[N],visl[N],x[N],y[N];
    inline ll power(ll x,ll y)
    {
        ll ans=1;
        while(y)
        {
            if(y&1) ans=ans*x%P;
            y>>=1;
            x=x*x%P;
        }
        return ans%P;
    }
    int main()
    {
    //    freopen("1.in","r",stdin);
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d%d%d",&n,&m,&k,&q);
            for(int i=1;i<=q;++i) scanf("%d%d",&x[i],&y[i]);
            for(int i=1;i<=max(n,m);++i) vish[i]=visl[i]=0;
            int cnt=0,cnth=0,cntl=0;
            for(int i=q;i>=1;--i)
            {
                if((cntl==m||vish[x[i]])&&(cnth==n||visl[y[i]])) continue;
                ++cnt;
                if(!vish[x[i]]) vish[x[i]]=1,cnth++;
                if(!visl[y[i]]) visl[y[i]]=1,cntl++;
            }
            printf("%lld\n",power(k,cnt));
        }
        return 0;
    }
    

    E. Expand the Path

    怎么说,这个题到最后还是没什么想法.....(还是我太菜了,又菜又爱生气.....)
    之前的想法一直是全部的路径叠加到一起看有没有什么规律....发现没有(我太菜了..)....
    但其实还有一种想法,就是我们可以统计下我们最多添加多少个D,添加多少个R。然后沿着原路径,对于每一个点来说如果他前面(包括它自己)只有D或只有R的话,说明我们在这个点的基础上将以他为端点的一行或一列的\(n-cnt_d或n-cnt_r\)个格点都覆盖掉,很简单的,我们可以在其基础上倍增D或R即可。之后在经过D与R之后的情况,我们可以通过倍增达到的区域就变成了一个\((n-cnt_d)\times(n-cnt_r)\)的长方形,每个点都对应一个矩形,我们的目的就是求所有的矩形的并。这可以直接采用扫描线的模板即可(正好我最怵这个东西,这次再写一遍..)。
    PS:补一下为什么还有这种想法,我们考虑原路径中,我们中途加了p次R,k次D,到达了某个点(x,y).那么假如说我们没有增加这R和D的情况下,我们本应到达的点应为(x-k,y-p).而p,k则由我们能添加的最大R和D的关系限制。所以这种方法和题意中是一一对应的。换言之,题目中能通过的所有的点,一定是在原路径上的某个点之前(包括自身),通过扩展D和R来达到的。现在我们枚举所有的点,将它通过扩展能到达的所有点的并一定是答案。

    点击查看代码
    #include<bits/stdc++.h>
    #define ls p<<1
    #define rs p<<1|1
    #define ll long long 
    using namespace std;
    const int N=2e5+10;
    char c[N];
    int T,n,m,b[N<<1],num;
    struct wy{int x,y1,y2,id;}a[N<<2];
    struct Tree
    {
        int l,r,len,dat;
        #define l(p) t[p].l
        #define r(p) t[p].r
        #define len(p) t[p].len
        #define dat(p) t[p].dat
    }t[N*20];
    inline bool cmp(wy a,wy b) {return a.x<b.x;}
    inline void build(int p,int l,int r)
    {
        l(p)=l;r(p)=r;
        len(p)=0;dat(p)=0;
        if(l==r) return;
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
    }
    inline int find(int x) {return lower_bound(b+1,b+num+1,x)-b;}
    inline void pushup(int p)
    {
        if(l(p)==r(p))
        {
            len(p)=dat(p)?b[l(p)+1]-b[l(p)]:0;
            return;
        }
        if(dat(p)) len(p)=b[r(p)+1]-b[l(p)];
        else len(p)=len(ls)+len(rs);
    }
    inline void alter(int p,int l,int r,int x)
    {
        if(l<=l(p)&&r>=r(p))
        {
            dat(p)+=x;
            pushup(p);
            return;
        }
        int mid=l(p)+r(p)>>1;
        if(l<=mid) alter(ls,l,r,x);
        if(r>mid)  alter(rs,l,r,x);
        pushup(p);
    }
    int main()
    {
    //    freopen("1.in","r",stdin); 
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%s",&n,c+1);
            m=strlen(c+1);
            int cntr=0,cntd=0;
            for(int i=1;i<=m;++i)
            {
                if(c[i]=='D') cntd++;
                else cntr++;
            }
            bool f1=false,f2=false;
            int x=1,y=1;num=0;
            for(int i=1;i<=m;++i)
            {
                if(c[i]=='D') f1=true,x++;
                if(c[i]=='R') f2=true,y++;
                int j=2*i-1,k=2*i;
                a[j].x=y;a[j].y1=x;a[j].y2=x+(f1?n-cntd:1);a[j].id=1;
                a[k].x=y+(f2?n-cntr:1);a[k].y1=x;a[k].y2=x+(f1?n-cntd:1);a[k].id=-1;
                b[++num]=x;b[++num]=x+(f1?n-cntd:1);
            }
            sort(a+1,a+2*m+1,cmp);
            sort(b+1,b+num+1);
            num=unique(b+1,b+num+1)-b-1;
            build(1,1,num-1);
            alter(1,find(a[1].y1),find(a[1].y2)-1,a[1].id);
            ll ans=0;
            for(int i=2;i<=2*m;++i)
            {
                ans+=(ll)len(1)*(a[i].x-a[i-1].x);
                alter(1,find(a[i].y1),find(a[i].y2)-1,a[i].id);
            }
            printf("%lld\n",ans+1);
        }
        return 0;
    }
    
  • 相关阅读:
    nodeJS入门01-http模块
    nodeJS入门-Buffer对象
    php与MySQL(php内置mysql函数)
    php与MySQL(基本操作)
    log4net
    js验证小数类型(浮点数)和整数类型
    牛腩学ASP.NET CORE做博客视频
    opencv再学习之路(八)---设定感兴趣区域(RIO)
    opencv再学习之路(四)---色彩分割得到二值图像
    opencv再学习之路(三)---形态学操作
  • 原文地址:https://www.cnblogs.com/gcfer/p/15928686.html
Copyright © 2020-2023  润新知