zoukankan      html  css  js  c++  java
  • cf自训6

    cf946D 背包+区间dp 好题

    /*
    先预处理出每行消去i个1后可以的到的最小时间:
        先求每行的前缀和,枚举左端点和右端点,消去的1 cost=tot-sum[r]+sum[l-1],区间长度=r-l+1
        time[cost]=min(time[cost],len) 
    然后再进行行间处理:
        就是n行删k个,转化为n组物品,然后总代价是k 
        分组背包做一下完事 
    dp[i][j]表示到第i行删了j个的最少上课时间 
    */ 
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 505
    int n,m,K,mp[maxn][maxn];
    int t[maxn][maxn],sum[maxn][maxn],dp[maxn][maxn];
    
    void init(){
        memset(t,0x3f,sizeof t);
        for(int i=1;i<=n;i++){
            t[i][sum[i][m]]=0;//全删完的情况 
            for(int l=1;l<=m;l++)
                for(int r=l;r<=m;r++){
                    int len=r-l+1;
                    int cost=sum[i][m]-(sum[i][r]-sum[i][l-1]);
                    t[i][cost]=min(t[i][cost],r-l+1);
                }
            }
    /*for(int i=1;i<=n;i++){
        for(int j=0;j<=sum[i][m];j++)
            cout<<t[i][j]<<" ";
        puts("");
    }*/
    }
    int main(){
        cin>>n>>m>>K;
        char ch;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++){
                cin>>ch;
                mp[i][j]=ch-'0';
                sum[i][j]=sum[i][j-1]+mp[i][j];
            }
        init();
        
        memset(dp,0x3f,sizeof dp);
        for(int j=0;j<=K;j++)dp[1][j]=t[1][j];
        for(int i=2;i<=n;i++)
            for(int j=0;j<=K;j++)
                for(int c=0;c<=j;c++)
                    dp[i][j]=min(dp[i][j],dp[i-1][j-c]+t[i][c]);
        
        int ans=0x3f3f3f3f;
        for(int j=0;j<=K;j++)
            ans=min(ans,dp[n][j]);
        cout<<ans<<endl;
    } 
    View Code

    cf893d 线段树区间更新,可以傻逼贪心做

    /*
    在每个0之前都要变成非负,这个非负数要尽量大。。
    先求前缀和数组,从左往右扫,找到第一个在0前的负值点,将其提高到允许的最大值x,然后后面统一+x
    线段树维护区间最大前缀和,然后从左往右扫,扫到ai=0时进行询问
    如果该点前缀和小于0那么将其提高,提高的上限lim=d-后面区间最大前缀和,如果lim+当前值<0,那么不可行 
    反之不进行操作
    对前缀和先判一下。。 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 100005
    #define ll long long  
    ll ans,n,d,a[maxn],sum[maxn],flag;
    
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    ll Max[maxn<<2],lazy[maxn<<2];
    void pushup(int rt){Max[rt]=max(Max[rt<<1],Max[rt<<1|1]);}
    void pushdown(int rt){
        if(lazy[rt]){
            lazy[rt<<1]+=lazy[rt];lazy[rt<<1|1]+=lazy[rt];
            Max[rt<<1]+=lazy[rt];Max[rt<<1|1]+=lazy[rt];
            lazy[rt]=0; 
        }
    }
    void build(int l,int r,int rt){
        if(l==r){Max[rt]=sum[l];return;}
        int m=l+r>>1;
        build(lson);build(rson);
        pushup(rt);
    } 
    void update(int L,int R,ll val,int l,int r,int rt){
        if(L<=l &&R>=r){lazy[rt]+=val;Max[rt]+=val;return;}
        int m=l+r>>1;
        pushdown(rt);
        if(L<=m)update(L,R,val,lson);
        if(R>m)update(L,R,val,rson);
        pushup(rt);
    }
    ll query(int L,int R,int l,int r,int rt){
        if(L<=l && R>=r)return Max[rt];
        pushdown(rt);
        int m=l+r>>1;ll res=-0x3f3f3f3f;
        if(L<=m)res=query(L,R,lson);
        if(R>m)res=max(res,query(L,R,rson));
        return res;
    }
    int main(){
        cin>>n>>d;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=1;i<=n;i++){sum[i]=sum[i-1]+a[i];if(sum[i]>d)flag=1;}
        if(flag){
            puts("-1");
            return 0;
        }
        build(1,n,1);
        for(int i=1;i<=n;i++){
            if(a[i]==0){
                int tmp=query(i,i,1,n,1);
                if(tmp>=0)continue;
                else{
                    int Max=query(i,n,1,n,1);
                    int lim=d-Max;
                    if(tmp+lim<0 || flag){
                        puts("-1");
                        return 0;
                    }
                    else {
                        update(i,n,lim,1,n,1);
                        ans++;
                    }
                }
            }
        }
        cout<<ans<<endl;
    }
    View Code

    cf797E 复杂度均摊成根号n级别,新题

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 120005
    int q,n,a[maxn];
    int dp[maxn][340];//dp[i][j]表示在位置i(p=i),k=j时的跳跃步数,dp[i][j]=dp[i+a[i]+j][j]+1 
    void init(){
        for(int j=1;j<=330;j++)
            for(int i=n;i>=1;i--){
                if(i+a[i]+j>n)dp[i][j]=1;
                else dp[i][j]=dp[i+a[i]+j][j]+1;
            }
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        init();
            
        cin>>q;
        while(q--){
            int ans=0,p,k;
            cin>>p>>k;
            if(k<=330){
                cout<<dp[p][k]<<'
    ';
                continue;
            }
            while(p<=n){
                p+=a[p]+k;
                ans++;
            }
            cout<<ans<<'
    ';
        }
    }
    View Code

    cf46D 线段树区间合并沙比提。。一个vector下标搞错弄了好久

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 120005
    int q,n,a[maxn];
    int dp[maxn][340];//dp[i][j]表示在位置i(p=i),k=j时的跳跃步数,dp[i][j]=dp[i+a[i]+j][j]+1 
    void init(){
        for(int j=1;j<=330;j++)
            for(int i=n;i>=1;i--){
                if(i+a[i]+j>n)dp[i][j]=1;
                else dp[i][j]=dp[i+a[i]+j][j]+1;
            }
    }
    int main(){
        cin>>n;
        for(int i=1;i<=n;i++)cin>>a[i];
        init();
            
        cin>>q;
        while(q--){
            int ans=0,p,k;
            cin>>p>>k;
            if(k<=330){
                cout<<dp[p][k]<<'
    ';
                continue;
            }
            while(p<=n){
                p+=a[p]+k;
                ans++;
            }
            cout<<ans<<'
    ';
        }
    }
    View Code
  • 相关阅读:
    【520】利用 TextBlob & Vader 进行情感分析
    【519】Visio 里面实现输入公式
    Xcode 复制多行/移动某行/删除多行 快捷键
    rosbag 时间和topic过滤
    卡方分布(Chi-squared)外点(outlier)剔除
    EVO使用方法详解
    CloudCompare分离点云地面点和非地面点
    slam方向期刊和会议汇总
    UrbanLoco数据集
    ElasticSearch学习笔记——ik分词添加词库
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10648277.html
Copyright © 2011-2022 走看看