zoukankan      html  css  js  c++  java
  • Codeforces Round #619 (Div. 2)

    Codeforces Round #619 (Div. 2)

    题目链接:https://codeforces.com/contest/1301

    A题跳过

    B题

    这题一开始跳了,后来回来用二分做的。二分答案,然后查询是否满足,查询用一个区间表示现在k 可以取值的范围。如果左端点比右端点大了,说明没有可能取值。但是,后来看了题解,发现直接取所有-1,两边的数的((最 大 值+最 小 值)/2)即为k。还是太菜了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    using vi=vector<int>;
    using pii=pair<int,int>;
    #define ll long long
     
    const int INF=1e9+7;
    const int N=500050;
    int a[N],n;
    int check(int x){
        int l=0,r=INF;
        for(int i=2;i<=n;i++){
            if (a[i]==-1){
                if (a[i-1]==-1) continue;
                l=max(l,a[i-1]-x);
                r=min(r,a[i-1]+x);
            }else if (a[i-1]==-1){
                l=max(l,a[i]-x);
                r=min(r,a[i]+x);
            }else{
                if (abs(a[i]-a[i-1])>x)return -1;
            }
            if (l>r)return -1;
        }
        return l;
    }
    int ef(int l,int r){
        if (l==r)return l;
        int mid=(l+r)>>1;
        if (check(mid)==-1)return ef(mid+1,r);
        else return ef(l,mid);
    }
    void work(){
        int num=0;
        cin>>n; 
        for(int i=1;i<=n;i++)cin>>a[i];
        
        int m=ef(0,INF);
        int k=check(m);
        cout<<m<<" "<<k<<endl;
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        int T;
        cin>>T;
        while(T--)work();
     
    }
    

    C. Ayoub's function

    贪心,肯定在0中间放1,连续的0的长度越短越好,就平均放1。然后算答案。

    至于为什么,假如连续的0的个数为(l),全为0的子串就有(l*(l+1)/2), 列出前面几项(1,3,6,10,15,21) 越往后,增加一个0就会增加更多的子串,所以要使得平均越短越好。

    代码

        #include<bits/stdc++.h>
        using namespace std;
        using vi=vector<int>;
        using pii=pair<int,int>;
        #define ll long long
         
        const int INF=0x7f7f7f7f;
        const int N=2000050;
        void work(){
            ll n,m,x,y;
            cin>>n>>m;
            if (m>=n-m+1){
                cout<<(n*(n+1)/2)-(n-m)<<endl;
                return;
            }
            x=(n-m)/(m+1);
            y=(n-m)%(m+1);
            ll ans=x*(x+1)/2*(m+1-y)+(x+1)*(x+2)/2*y;
            ans=(n*(n+1))/2-ans;
            cout<<ans<<endl;
        }
        int main(){
        #ifndef ONLINE_JUDGE
            freopen("aa.in","r",stdin);
        #endif
            ios::sync_with_stdio(false);
            cin.tie(0);
            int T;
            cin>>T;
            while(T--)work();
         
        }
         
    

    D. Time to Run

    题解

    先找一种方法,可以走完所有的边。我是先一直往右走,走到底(1,m),再走回(1,1)。

    之后就先往下走一格,再“RUL”不断重复往右边走,走到底再往左直走回来。

    如此循环,直到最后停在(n,1) ,这时再往上走回(1,1).

    知道怎么走之后,关键就是怎么输出了。我可真是不太行,于是就去看大佬的代码,发现太巧妙了。就是先将这些步骤全部以pair打入一个vector中,first存重复多少次,second存怎么走。每个pair就相当于一个二维数组一样。比如元素a,

    a.first*b.size()就是这个二维数组的大小。然后就一个一个块扫,如果大于整个快,就直接算答案,如果小于快,就在内部处理。总之就是很方便,代码很短很容易理解。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define fi first
    #define se second
     
    typedef long long ll;
     
    const int INF=1e9+7;
    const int N=500050;
    vector<pair<int,string>> ans,pans;
    void work(){
        int n,m,k;
        cin>>n>>m>>k;
        if (k>4*n*m-2*n-2*m){
            puts("NO");
            return;
        }
        ans.push_back({m-1,"R"});
        ans.push_back({m-1,"L"});
        for(int i=1;i<=n-1;i++){
            ans.push_back({1,"D"});
            ans.push_back({m-1,"RUD"});
            ans.push_back({m-1,"L"});
        }
        ans.push_back({n-1,"U"});
        for(auto x:ans){
            if (x.fi==0)continue;//这里主要是防止m=1的情况
            if (x.fi*x.se.size()<=k){
                pans.push_back(x);
                k-=x.fi*x.se.size();
            }else{
                if (k/x.se.size())pans.push_back({k/x.se.size(),x.se});
                if (k%x.se.size())pans.push_back({1,x.se.substr(0,k%x.se.size())});
                k=0;
            }
        }
        cout<<"YES"<<endl;
        cout<<pans.size()<<endl;
        for(auto x:pans)cout<<x.fi<<" "<<x.se<<endl;
    }
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("aa.in","r",stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        work();
     
    }
    

    E. Nanosoft

    题解

    解法一 (O(n^2log^2n + qlogn))

    这个分成两个部分,也是std的做法。

    第一步,先求每个点,为中间点,往外的logo的最长边长。我是用左上的正方形的右下角当中间点。

    定以:

    1. (c[x][y]) 以(x,y)坐标表示左上角的logo的边长
    2. (b[x][y]) 以(x,y)坐标为中间点的logo的最大边长,也就是红色正方形的右下角那个点。

    先求(c[x][y]。)

    • 当最外面一圈合法时:(c[x][y]=c[x+1][y+1]+2)
    • 当最外面一圈不合法:(c[x][y]=0)

    扫描最外面一圈,我是直接暴力,我觉得这个是(O(n^2))因为除了每个logo的最外层,其他的点不会被扫到两遍。之后再用(c[x][y]求b[x][y]),这个很好求,扫描一遍(对于每一个c[x][y],b[x+c[x][y]/2-1][y+c[x][y]/2-1]=max(c[x][y],自己)).

    第二步,用二分+sparse table求结果。

    二分答案,然后用二维ST表求最大值是否大于答案,需要注意边界问题。假如我们现在枚举答案为len(实际边长为2*len),区间为(r1,c1)~(r2,c2)。则实际求最大值的范围为(r1+len-1,c1+len-1)~(r2-len,c2-len)。因为左上角和右下角的值都会越出边界。大概思路就是这样。我不知道为什么我的代码跑起来就是慢。

    解法二 (O(n^3+qn))

    这个方法简单暴力,但是速度也不慢,因为常数很小,因为(nle 500)所以其实(n和log^2n)差不多。

    定义:

    1. (cnt[k][x][y]) 矩阵((1,1)~(x,y))的颜色(k(k<4))的个数。
    2. (ans[l][x][y]) 以(x,y)为左上角的logo的边长为(2*l)是否存在,存在为1
    3. (sans[l][x][y]) (ans[l][x][y])的二维前缀和=(sum_{i=1}^xsum_{j=1}^y ans[l][i][j])

    这几个东西都很好求,就是二维前缀和。然后求答案,就每一种答案都判断所求举证里的二维前缀和是否大于零。边界问题还是要注意,这里不讲了。当然也可以二分。

    代码一 ST+二分答案 (O(n^2log^2n))

        #include<bits/stdc++.h>
        using namespace std;
        const int N = 505;
        struct Square{int x1,y1,x2,y2;};
        char mp[N][N];
        int b[N][N],c[N][N];
        struct ST{
            int mx[N][N][10][10],mi[10],lg[N];
            void build(int c[N][N],int n, int m){
                lg[0]=-1;
                for(int i=1;i<=max(n,m);i++)lg[i]=lg[i>>1]+1;
                for(int i=0;i<10;i++)mi[i]=1<<i;
                for(int i=1;i<=n;i++)
                    for(int j=1;j<=m;j++)
                        mx[i][j][0][0]=c[i][j];
                for(int k=1;k<10;k++)
                    for(int i=1;i<=n;i++)
                        for(int j=1;j+mi[k]-1<=m;j++){
                            mx[i][j][0][k]=max(mx[i][j][0][k-1],mx[i][j+mi[k-1]][0][k-1]);
                        }
                int x,y;
                for(int k1=1;k1<10;k1++)
                    for(int k2=0;k2<10;k2++)
                        for(int i=1;i+mi[k1]-1<=n;i++)
                            for(int j=1;j+mi[k2]-1<=m;j++){
                                x=max(mx[i][j][k1-1][k2],mx[i+mi[k1-1]][j][k1-1][k2]);
                                mx[i][j][k1][k2]=x;
                            }
            }
            int get(int x1, int y1, int x2, int y2){
                if (x1>x2 || y1>y2)return 0;
                int k1=lg[x2-x1+1], k2=lg[y2-y1+1],val1,val2;
                x2-=mi[k1]-1; y2-=mi[k2]-1;
                val1=max(mx[x1][y1][k1][k2],mx[x1][y2][k1][k2]);
                val2=max(mx[x2][y1][k1][k2],mx[x2][y2][k1][k2]);
                return max(val1,val2);
            }
        }St;
        bool check(int x, int y, int len){
            for(int i=0;i<len/2;i++){
                if (mp[x][y+i]!='R') return 0;
                if (mp[x][y+len/2+i]!='G') return 0;
                if (mp[x+len-1][y+i]!='Y') return 0;
                if (mp[x+len-1][y+len/2+i]!='B') return 0;
                if (mp[x+i][y]!='R') return 0;
                if (mp[x+len/2+i][y]!='Y') return 0;
                if (mp[x+i][y+len-1]!='G') return 0;
                if (mp[x+len/2+i][y+len-1]!='B')return 0;
            }
            return 1;
        }
        bool efcheck(Square a, int len ){
            a.x1+=len-1; a.y1+=len-1;
            a.x2-=len; a.y2-=len;
            if (St.get(a.x1,a.y1,a.x2,a.y2)>=len)return 1;
            return 0;
        }
        int ef(Square a,int l,int r){
            if (l==r)return l;
            int mid=(l+r+1)>>1;
            if (efcheck(a,mid))return ef(a,mid,r);
            else return ef(a,l,mid-1);
        }
        int main(){
            #ifndef ONLINE_JUDGE
            freopen("aa.in","r",stdin);
            #endif
            ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
            int n,m,k;
            cin>>n>>m>>k;
            for(int i=1;i<=n;i++)
                cin>>mp[i]+1;
            for(int i=n;i>=1;i--)
                for(int j=m;j>=1;j--){
                    int x=i+1, y=j+1;
                    if (x>n || y>m)continue;
                    if (check(i,j,c[i+1][j+1]+2))
                        c[i][j]=c[i+1][j+1]+2;
                }
            for(int i=1;i<n;i++)
                for(int j=1;j<m;j++){
                    if (c[i][j]==0) continue;
                    int x=i+c[i][j]/2-1, y=j+c[i][j]/2-1;
                    b[x][y]=max(b[x][y],c[i][j]/2);
            }
            St.build(b,n,m);
            //cout<<St.get(1,1,n,m)<<endl;
            int x1,y1,x2,y2,ans;
            for(int i=1;i<=k;i++){
                cin>>x1>>y1>>x2>>y2;
                Square a={x1,y1,x2,y2};
                ans=ef(a,0,x2-x1+1);
                ans*=ans*4;
                cout<<ans<<endl;
            }
            
        }
    

    代码二 暴力枚举答案 (O(n^3+q n))

        #include<bits/stdc++.h>
        using namespace std;
        const int N=505;
        string col="RGYB";
        int n,m,q,cnt[255][N][N];
        char grid[N][N];
        int get(int k,int x1,int y1,int x2,int y2){
            return cnt[k][x2][y2]-cnt[k][x1-1][y2]-cnt[k][x2][y1-1]+cnt[k][x1-1][y1-1];
        }
        int main(){
            scanf("%d%d%d",&n,&m,&q);
            for(int i=1;i<=n;i++) scanf("%s",grid[i]+1);
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    for(int k=0;k<4;k++)
                        if (grid[i][j]==col[k])cnt[k][i][j]=1;
            for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=0;k<4;k++)cnt[k][i][j]+=cnt[k][i-1][j];
            for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=0;k<4;k++)cnt[k][i][j]+=cnt[k][i][j-1];
            for(int l=1;l<=250;l++){
                if (2*l>n || 2*l>m) break;
                for(int x=l;x<=n-l;x++)
                    for(int y=l;y<=m-l;y++){
                        if (get(0,x-l+1,y-l+1,x,y)!=l*l)continue;
                        if (get(1,x-l+1,y+1,x,y+l)!=l*l)continue;
                        if (get(2,x+1,y-l+1,x+l,y)!=l*l)continue;
                        if (get(3,x+1,y+1,x+l,y+l)!=l*l)continue;
                        cnt[l+3][x-l+1][y-l+1]=1;
                    }
                for(int i=1;i<=n-2*l+1;i++)
                    for(int j=1;j<=m-2*l+1;j++)
                        cnt[l+3][i][j]+=cnt[l+3][i-1][j];
                for(int i=1;i<=n-2*l+1;i++)
                    for(int j=1;j<=m-2*l+1;j++)
                        cnt[l+3][i][j]+=cnt[l+3][i][j-1];
            }
            int r1,c1,r2,c2,ans;
            for(int i=1;i<=q;i++){
                scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
                ans=0; r2++; c2++;
                for(int l=1;l<=250;l++){
                    r2-=2; c2-=2;
                    if (r1>r2 || c1>c2)break;
                    if (get(l+3,r1,c1,r2,c2)>0)ans=l;
                }
                ans=ans*ans*4;
                printf("%d
    ",ans);
            }
        }
    

    F. Super Jaber

    题解:

    关键就是颜色只有40种,我们先考虑如果不通过相同颜色传送,那么虽短举例就是两点的曼哈顿举例,也就是(|(r2-r1)|+|(c2-c1)|)

    那么我们假设至少用一次传送,我们就可以枚举哪个颜色一定会用传送。我们可以预处理出来每个点到某种颜色的最短距离。

    定义:

    • (dist[k][i][j]:(i,j) ightarrow颜色k 的最短路径(可以传送))

    那么枚举(k)((r1,c1) ightarrow(r2,c2)最短距离=min{ dist[k][r1][c1]+dist[k][r2][c2]+1})

    (dist)数组就用(bfs),每种颜色做一遍(bfs),注意一下扩展相同颜色就行了。

    代码:

        #include<bits/stdc++.h>
        using namespace std;
        typedef pair<int,int> pii;
        typedef vector<pair<int,int>> vpii;
         
        const int N=1050;
        const int K=45;
        int n,m,k;
        int grid[N][N],dist[K][N][N];
        int lx[4]={1,-1,0,0};
        int ly[4]={0,0,-1,1};
        deque<pii> color[K];
        void bfs(int dist[N][N], deque<pii> Q){
            static int f[K];
            memset(f,0,sizeof(f));
            while(!Q.empty()){
                pii u=Q.front(); Q.pop_front();
                int x=u.first, y=u.second;
                if(f[grid[x][y]]==0){
                    f[grid[x][y]]=1;
                    auto it=color[grid[x][y]].begin();
                    for(;it!=color[grid[x][y]].end();it++){
                        int xx=it->first, yy=it->second;
                        if (dist[xx][yy]<=dist[x][y]+1)continue;
                        dist[xx][yy]=dist[x][y]+1;
                        Q.push_back({xx,yy});
                    }
                }
                for(int i=0;i<4;i++){
                    int xx=x+lx[i], yy=y+ly[i];
                    if (xx<1 || xx>n || yy<1 || yy>m)continue;
                    if (dist[x][y]+1>=dist[xx][yy])continue;
                    dist[xx][yy]=dist[x][y]+1;
                    Q.push_back({xx,yy});
                }
            }
        }
        int main(){
            #ifndef ONLINE_JUDGE
            freopen("aa.in","r",stdin);
            #endif
            scanf("%d%d%d",&n,&m,&k);
            memset(dist,63,sizeof(dist));
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++){
                    scanf("%d",grid[i]+j);
                    color[grid[i][j]].push_back({i,j});
                    dist[grid[i][j]][i][j]=0;
                }
            for(int i=1;i<=k;i++)bfs(dist[i],color[i]);
            int q;
            scanf("%d",&q);
            while(q--){
                int r1,c1,r2,c2;
                scanf("%d%d%d%d",&r1,&c1,&r2,&c2);
                int ans=abs(r1-r2)+abs(c2-c1);
                for(int i=1;i<=k;i++)
                    ans=min(ans,dist[i][r1][c1]+dist[i][r2][c2]+1);
                cout<<ans<<endl;
            }
        }
    
  • 相关阅读:
    TCP/IP 三次握手四次挥手
    光端机2m是什么意思,光端机E1与2M有什么区别?
    电视光端机故障维护与指示灯说明
    电视光端机常见故障问题介绍
    传输设备,光端机的应用及故障分析
    RS485数据光端机产品特点及技术参数介绍
    网管交换机与非网管交换机的优缺点介绍
    网管型交换机相比普通交换机有哪些明显优势?
    什么叫POE交换机?POE交换机使用方法详解!
    交换机用光纤模块互连一端灯不亮或两端都不亮,如何处理?
  • 原文地址:https://www.cnblogs.com/mmmqqdd/p/12407648.html
Copyright © 2011-2022 走看看