2017.10.21离线赛总结

square ——2994

思路:强模拟…

lis ——2995

思路:dp,先算总方案数,再将对应得位置判一下。

paint ——3798

思路:看过题意,应该条件反射出二分答案,又因为n=2,也就是说,要么第1行画到i位置,第2行画到j位置,或者同时画到k位置。就很容易想到dp
每一次check时的dp,有很多是冗余的,便可预处理出来。这样达到的效果就应当于跳着画。

#include<bits/stdc++.h>
#define REP(i,f,t) for(int i=(f),i##_end_=(t);i<=i##_end_;i++)
#define DREP(i,f,t) for(int i=(f),i##_end_=(t);i>=i##_end_;i--)
#define INF 0x3f3f3f3f
#define LL long long
#define N 20005
#define M 105
using namespace std;
int n,m;
LL tot;
int A[2][N];
struct p20{
    int sum[3][N];
    bool dp[200][200]; 
    bool check(LL x){
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        REP(l,1,m)DREP(i,n,0)DREP(j,n,0){
            if(!dp[i][j])continue;
            if(i==j){
                REP(k,i+1,n){
                    if(sum[2][k]-sum[2][i]>x)break;
                    dp[k][k]=1;
                }
            }
            REP(k,i+1,n){
                if(sum[0][k]-sum[0][i]>x)break;
                dp[k][j]=1;
            }
            REP(k,j+1,n){
                if(sum[1][k]-sum[1][j]>x)break;
                dp[i][k]=1; 
            }
        }
        return dp[n][n];
    }
    void solve(){
        REP(i,0,1)REP(j,1,n)sum[i][j]+=sum[i][j-1]+A[i][j];
        REP(i,1,n)sum[2][i]+=sum[0][i]+sum[1][i];
        LL L=tot/m,R=tot,ans;
        while(L<=R){
            LL mid=(L+R)>>1;
            if(check(mid))ans=mid,R=mid-1;
            else L=mid+1;
        }
        cout<<ans<<endl;
    }
}p20;
struct p40{
    LL sum[3][505];
    bool dp[750][750];
    bool check(LL mx){
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        REP(l,1,m)DREP(i,n,0)DREP(j,n,0){
            if(!dp[i][j])continue;
            if(i==j){
                int k=upper_bound(sum[2]+i,sum[2]+n+1,sum[2][i]+mx)-sum[2]-1;
                dp[k][k]=1;
            }
            int k=upper_bound(sum[0]+i,sum[0]+n+1,sum[0][i]+mx)-sum[0]-1;
            if(k>j)dp[j][j]=1;
            dp[k][j]=1;
            k=upper_bound(sum[1]+j,sum[1]+n+1,sum[1][j]+mx)-sum[1]-1;
            if(k>i)dp[i][i]=1;
            dp[i][k]=1;
        }
        return dp[n][n];
    }
    void solve(){
        REP(i,0,1)REP(j,1,n)sum[i][j]+=sum[i][j-1]+A[i][j];
        REP(i,1,n)sum[2][i]+=sum[1][i]+sum[0][i];
        LL L=tot/m,R=tot,ans=0;
        while(L<=R){
            LL mid=(L+R)>>1;
            if(check(mid))ans=mid,R=mid-1;
            else L=mid+1;
        }
        cout<<ans<<endl;
    }
}p40;
struct p80{
    int dp[N];
    bool check(LL x){
        memset(dp,INF,sizeof(dp));
        dp[0]=0;
        REP(i,1,n){
            int s0=0,s1=0,cnt=0;
            DREP(j,i,1){
                if(s0+A[0][j]>x)cnt++,s0=0;
                if(s1+A[1][j]>x)cnt++,s1=0;
                s0+=A[0][j],s1+=A[1][j];
                dp[i]=min(dp[i],dp[j-1]+cnt+(s0>0)+(s1>0));
            }
            int s2=0;cnt=0;
            DREP(j,i,1){
                if(s2+A[0][j]+A[1][j]>x)cnt++,s2=0;
                s2+=A[0][j]+A[1][j];
                if(s2>x)break;
                dp[i]=min(dp[i],dp[j-1]+cnt+(s2>0));
            }
            if(dp[i]>m)return 0;
        }
        return dp[n]<=m;
    }
    void solve(){
        LL L=tot/m,R=tot,ans=0;
        while(L<=R){
            LL mid=(L+R)>>1;
            if(check(mid))ans=mid,R=mid-1;
            else L=mid+1;
        }
        cout<<ans<<endl;
    }
}p80;
struct p100{
    int dp[N],sum[3][N],nxt[3][N];
    void chkmin(int &x,int y){if(x>y)x=y;}
    bool check(LL x){
        memset(dp,63,sizeof(dp));
        dp[0]=0;
        REP(i,0,2){
            int L=1,R=1;
            while(L<=n){
                while(R<=n && sum[i][R]-sum[i][L-1]<=x)R++;
                nxt[i][L]=R-1;
                L++;
            }
        }
        REP(i,0,n-1){
            if(dp[i]==INF)continue;
            int cnt=2,a=nxt[0][i+1],b=nxt[1][i+1];
            chkmin(dp[nxt[2][i+1]],dp[i]+1);
            while(a!=n || b!=n){
                chkmin(dp[min(a,b)],dp[i]+cnt);
                if(a<b)a=nxt[0][a+1];
                else b=nxt[1][b+1];
                cnt++;
                if(cnt+dp[i]>m)break;
            }
            if(a==n && b==n)chkmin(dp[n],dp[i]+cnt);
            if(dp[n]<=m)return 1;
        }
        return dp[n]<=m;
    }
    void solve(){
        REP(i,0,1)REP(j,1,n)sum[i][j]+=sum[i][j-1]+A[i][j];
        REP(i,1,n)sum[2][i]+=sum[1][i]+sum[0][i];       
        LL L=1,R=tot,ans=0;
        while(L<=R){
            LL mid=(L+R)>>1;
            if(check(mid))ans=mid,R=mid-1;
            else L=mid+1;
        }
        cout<<ans<<endl;
    }
}p100;
int main(){
    scanf("%d%d",&n,&m);
    REP(i,0,1)REP(j,1,n)scanf("%d",&A[i][j]),tot+=A[i][j];
    p100.solve(); 
    return 0;
}

小结:今天第一题题目看错,我也无fuck可说…总体就是炸了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值