2050 Programming Competition部分题解(前7题 所有区间的min值之和-单调栈)

链接: http://2050.acmclub.cn/contests/contest_show.php?cid=3

7题,排名52,个人感觉还不错^_^

A-开场白

#include<bits/stdc++.h>
using namespace std;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;cin>>t;
    while(t--){
        string x;cin>>x;

        while(x.length()>=4){
            if(x.substr(0,4)=="2050"){
                x.erase(0,4);
            }
            else break;
        }
        if(x=="")printf("Yes\n");
        else printf("No\n");
    }
}

B-时间间隔

因为要模100,所以小时是没有用的(60*60%100=0),直接算当前离整点的时间即可

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)

int ct[1009];
int sum[1009];
int main(){
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        int y,m,d,h,mm,s;
        scanf("%d-%d-%d %d:%d:%d",&y,&m,&d,&h,&mm,&s);
        printf("%d\n",(60*60-mm*60-s)%100);
    }
    return 0;

}

C-分宿舍

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=a;i<=b;i++)
const int maxn=5009;
LL dp[maxn],a[5];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        LL n,m,k,b,c;
        cin>>n>>m>>k>>a[2]>>a[3]>>c;
        rep(i,1,5000)
            dp[i]=1e18;
        dp[0]=0;
        dp[1]=min(a[2],a[3]);
        dp[2]=min(2*a[2],a[3]);
        rep(i,2,5000){
            rep(j,2,3){
                if(i<j)
                    continue;
                if(dp[i-j]==1e18)
                    continue;
                dp[i]=min(dp[i],dp[i-j]+a[j]);
            }
        }
        for(int i=4999;i>=1;i--)
            dp[i]=min(dp[i],dp[i+1]);
        LL ans=1e18;
        for(LL i=0;i<=k;i++){
            ans=min(ans,dp[n+i]+dp[m+i]+(k-i)*c);
        }
        cout<<ans<<endl;
    }
    return 0;
}

D-PASS

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)

int ct[1009];
int sum[1009];
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;cin>>t;
    while(t--){
        int n,m,k;
        cin>>n>>m>>k;
        rep(i,1,m)ct[i]=sum[i]=0;
        rep(i,1,n){
            int tmp;cin>>tmp;sum[tmp]++;
            if(i<=n/2)ct[tmp]++;
        }
        int ans=0;
        rep(i,1,m){
            int kk=sum[i]/k;
            kk=min(kk,ct[i]);
            ans+=kk;
        }
        cout<<ans<<endl;
    }
}

E-球赛

dp[i][j][k]表示到了点i,j个A,k个B的最大比赛数。因为11-10和10-9是一样的,所以状态数只有11*11

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,b,a) for(int i=b;i>=a;i--)
#define LL long long
int dp[10009][15][15];
char x[10009];
int main(){
    //ios::sync_with_stdio(false);
    //cin.tie(0);
    int t;
    cin>>t;

    while(t--){
        memset(dp,0xc0,sizeof dp);
        scanf("%s",x+1);
        dp[0][0][0]=0;
        int len=strlen(x+1);
        int jj,kk;
        rep(i,1,len){
            rep(j,0,10){
                rep(k,0,10){
                    if(dp[i-1][j][k]<0)continue;
                    if(x[i]=='A')
                        jj=j+1,kk=k;
                    else if(x[i]=='B')
                        jj=j,kk=k+1;
                    else
                        jj=j,kk=k+1;

                    if(jj<11&&kk<11){
                        dp[i][jj][kk]=max(dp[i][jj][kk],dp[i-1][j][k]);
                    }
                    else if(jj==11){
                        if(kk<10){
                            dp[i][0][0]=max(dp[i][0][0],dp[i-1][j][k]+1);
                        }
                        else {
                            dp[i][jj-1][kk-1]=max(dp[i][jj-1][kk-1],dp[i-1][j][k]);
                        }
                    }
                    else if(kk==11){
                        if(jj<10){
                            dp[i][0][0]=max(dp[i][0][0],dp[i-1][j][k]+1);
                        }
                        else {
                            dp[i][jj-1][kk-1]=max(dp[i][jj-1][kk-1],dp[i-1][j][k]);
                        }
                    }

                    if(x[i]=='?'){
                        jj=j+1,kk=k;

                        if(jj<11&&kk<11){
                            dp[i][jj][kk]=max(dp[i][jj][kk],dp[i-1][j][k]);
                        }
                        else if(jj==11){
                            if(kk<10){
                                dp[i][0][0]=max(dp[i][0][0],dp[i-1][j][k]+1);
                            }
                            else {
                                dp[i][jj-1][kk-1]=max(dp[i][jj-1][kk-1],dp[i-1][j][k]);
                            }
                        }
                        else if(kk==11){
                            if(jj<10){
                                dp[i][0][0]=max(dp[i][0][0],dp[i-1][j][k]+1);
                            }
                            else {
                                dp[i][jj-1][kk-1]=max(dp[i][jj-1][kk-1],dp[i-1][j][k]);
                            }
                        }
                    }
                }
            }
        }
        int ans=0;
        rep(i,0,10){
            rep(j,0,10){
                ans=max(ans,dp[len][i][j]);
            }
        }
        printf("%d\n",ans);
    }
    return 0;

}

F-冰水挑战

dp[i][j]表示到了点i,完成j个的最大体力。注意要longlong

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,b,a) for(int i=b;i>=a;i--)
#define LL long long
LL dp[1009][1009];

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;
    while(t--){
        memset(dp,0xc0,sizeof(dp));
        LL n,cc;cin>>n>>cc;

        dp[0][0]=cc;
        rep(i,1,n){
            LL a,b,c;cin>>a>>b>>c;
            rep(j,0,i-1){
                if(dp[i-1][j]<=0)continue;
                dp[i][j]=max(dp[i][j],dp[i-1][j]+c);
                if(min(dp[i-1][j],b)-a>0){
                    dp[i][j+1]=max(dp[i][j+1],min(dp[i-1][j],b)-a+c);
                }
            }
        }
        int ans=0;
        repp(i,n,1){
            if(dp[n][i]>0){
                ans=i;break;
            }
        }
        cout<<ans<<endl;
    }
    return 0;

}

G-大厦

先将第一种排好,再一条一条插入第二种(从上到下)。
在这里插入图片描述
在这里插入图片描述
对于当前线,算出于其交与矩形内的左右边界,对边界内的段的累加器+1。我们再计算出以当前线为底(直线的左上方)有多少个矩形。转换为下图:
在这里插入图片描述
显然答案= i j m i n ( c t [ i ] , c t [ j ] ) \sum_{i\to j}min(ct[i],ct[j]) ,上图的答案为(2+3+4+3+3+2)+(min(2,3)…)+(min(2,3,4)…)…即任意区间的min值之和。

这个可以用单调栈来做,用sum来维护栈内所有值之和。下面是栈的维护过程,具体看代码:
在这里插入图片描述

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repp(i,b,a) for(int i=b;i>=a;i--)
#define LL long long

const LL mod=1e9+7;
int a[1009],b[1009],ct[1009];int w,h,n,m;
bool in(double x,double y){
    if(x<0||y<0||x>w*1.0||y>h*1.0)return 0;
    return 1;
}
int sta[1009],top;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin>>t;

    while(t--){
       rep(i,1,1000)ct[i]=-1;
        cin>>w>>h>>n>>m;
        rep(i,1,n)cin>>a[i];
        rep(i,1,m)cin>>b[i];
        sort(a+1,a+1+n);
        sort(b+1,b+1+m);
        double x,y;

        LL Ans=0;
        rep(i,1,m){
            int l=-1,r=-1;
            rep(j,1,n){
                x=(a[j]+b[i])*1.0/2;
                y=x-b[i]*1.0;
                if(in(x,y)){l=j;break;}
            }
            if(l==-1)continue;
            repp(j,n,1){
                x=(a[j]+b[i])*1.0/2;
                y=x-b[i]*1.0;
                if(in(x,y)){r=j;break;}
            }

            rep(j,l,r-1){
                ct[j]++;
            }
            //单调栈
            top=0;
            LL sum=0;
            rep(j,l,r-1){
                while(top&&ct[j]<=ct[sta[top]]){
                    if(top==1){
                        sum=0;
                    }
                    else{
                        sum=((sum-(LL)ct[sta[top]]*(LL)(sta[top]-sta[top-1]))%mod+mod)%mod;
                    }
                    top--;
                }
                sta[++top]=j;
                if(top==1)
                    sum=(LL)ct[j]*(LL)(j-l+1)%mod;
                else
                    sum=(sum+ct[j]*(LL)(j-sta[top-1]))%mod;
                Ans=(Ans+sum)%mod;
            }
        }
        cout<<Ans<<endl;
    }
    return 0;

}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/89289677