美文网首页
常用技巧(二)

常用技巧(二)

作者: 云中翻月 | 来源:发表于2019-09-29 17:20 被阅读0次

    POJ 3250: Bad Hair Day
    题意:统计每个数字右边第一个比它大的数字与它的下标差的和。
    单调栈模板题。(相当于只从一头进出的单调严格递减栈)
    然后反过来思考,统计每头牛被多少头牛看到,作为这头牛对答案的贡献即可。
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    题意:统计每个数字右边第一个比它大的数字与它的下标差的和。
    单调栈模板题。(相当于只从一头进出的单调严格递减栈) 
    然后反过来思考,统计每头牛被多少头牛看到,作为这头牛对答案的贡献即可。 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=80000+5;
    const int INF=0x3f3f3f3f;
    int q[maxn],n,h[maxn];
    ll ans=0ll;
    void solve(){
        int head=1,tail=1;
        q[head]=1;
        for(int i=2;i<=n+1;i++){
            while(head<=tail&&h[q[tail]]<=h[i]) tail--;
            ans+=(ll)(tail-head+1); //此时栈中的元素都能看到i 即i的贡献就是栈中元素的数量tail-head+1 
            q[++tail]=i;
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
        //freopen("Bad Hair Day.in","r",stdin);
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&h[i]);
        h[n+1]=INF;
        solve();
        printf("%lld",ans);
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    POJ 2082: Terrible Sets
    预处理出l[i]和r[i]为i号矩形向左/右能够达到的最远小标距离,可以用两个严格单调增的单调栈实现。
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    预处理出l[i]和r[i]为i号矩形向左/右能够达到的最远小标距离,可以用两个严格单调增的单调栈实现。 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=50000+5;
    const int INF=0x3f3f3f3f;
    int w[maxn],h[maxn],n;
    int ans;
    int q[maxn],l[maxn],r[maxn];
    void init(){
        ans=0;
    }
    void solve(){
        int head=1,tail=1;
        q[head]=0;
        h[0]=-INF;
        for(int i=1;i<=n;i++){
            while(head<=tail&&h[i]<=h[q[tail]]) tail--;
            l[i]=w[i]-w[q[tail]];
            q[++tail]=i;
        }
    //  for(int i=1;i<=n;i++) D(l[i]);
    //  E;
        head=1,tail=1;
        q[head]=n+1;
        h[n+1]=-INF;
        for(int i=n;i>=1;i--){
            while(head<=tail&&h[i]<=h[q[tail]]) tail--;
            r[i]=w[q[tail]-1]-w[i-1];
            q[++tail]=i;
        }
    //  for(int i=1;i<=n;i++) D(r[i]);
    //  E;
        for(int i=1;i<=n;i++) ans=max((l[i]+r[i]-w[i]+w[i-1])*h[i],ans);
    }
    int main() {
    //  ios::sync_with_stdio(false);
        //freopen("Terrible Sets.in","r",stdin);
        while(scanf("%d",&n)){
            if(n==-1) break;
            init();
            for(int i=1;i<=n;i++){
                scanf("%d%d",&w[i],&h[i]);
                w[i]+=w[i-1];
            }
            solve();
            printf("%d\n",ans);
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    POJ 3494: Largest Submatrix of All 1’s
    悬线法裸题,不再赘述。
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    悬线法裸题,不再赘述。 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=2000+5;
    const int INF=0x3f3f3f3f;
    int n,m,a[maxn][maxn],q[maxn],h[maxn],l[maxn],r[maxn],ans;
    void init(){
        ans=0;
    }
    int calc(){ //计算h[i]表示的最大矩形 
        int res=0;
    //  for(int i=1;i<=m;i++) D(h[i]);
    //  E;
        int head=1,tail=1;
        q[head]=0;
        h[0]=-INF;
        for(int i=1;i<=m;i++){
            while(head<=tail&&h[i]<=h[q[tail]]) tail--;
            l[i]=i-q[tail];
            q[++tail]=i;
        }
    //  for(int i=1;i<=m;i++) D(l[i]);
    //  E;
        head=1,tail=1;
        q[head]=m+1;
        h[m+1]=-INF;
        for(int i=m;i>=1;i--){
            while(head<=tail&&h[i]<=h[q[tail]]) tail--;
            r[i]=q[tail]-i;
            q[++tail]=i;
        }
    //  for(int i=1;i<=m;i++) D(r[i]);
    //  E;
        for(int i=1;i<=m;i++) res=max((l[i]+r[i]-1)*h[i],res);
        return res;
    }
    void solve(){
        for(int i=1;i<=n;i++){
            memcpy(h,a[i],sizeof(a[i]));
            ans=max(calc(),ans);
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
        //freopen("Largest Submatrix of All 1’s.in","r",stdin);
        while(scanf("%d%d",&n,&m)!=EOF) {
            init(); 
            for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) {
                    scanf("%d",&a[i][j]);
                    if(a[i][j]!=0) a[i][j]+=a[i-1][j];
                }
            /*
            for(int i=1; i<=n; i++) {
                for(int j=1; j<=m; j++) {
                    cout<<a[i][j]<<" ";
                }
                E;
            }
            */
            solve();
            printf("%d\n",ans);
        }
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    双端队列

    POJ 2823: Sliding Window
    单调队列模板题,不再赘述。
    注意k=1的情况。
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    单调队列模板题,不再赘述。
    注意k=1的情况。  
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=1e6+5;
    const int INF=0x3f3f3f3f;
    int n,k,a[maxn];
    int q[maxn];
    int mn[maxn],mx[maxn]; //最小值 最大值 
    void solve(){
        int head=1,tail=1;
        q[head]=1;
        mn[1]=mx[1]=a[1]; //注意k=1的情况 
        //1 3 -1 -3 5 3 6 7
        for(int i=2;i<=n;i++){
            while(head<=tail&&i-q[head]+1>k) head++; //i-q[head]+1为单调队列中的元素数量 
            while(head<=tail&&a[i]<=a[q[tail]]) tail--;
            q[++tail]=i;
    //      for(int j=head;j<=tail;j++) D(a[q[j]]);
    //      E;
            mn[i]=a[q[head]];
        }
        head=1,tail=1;
        q[head]=1;
        for(int i=2;i<=n;i++){
            while(head<=tail&&i-q[head]+1>k) head++; 
            while(head<=tail&&a[i]>=a[q[tail]]) tail--;
            q[++tail]=i;
    //      for(int j=head;j<=tail;j++) D(a[q[j]]);
    //      E;
            mx[i]=a[q[head]];
        }
    }
    int main() {
    //  ios::sync_with_stdio(false);
        //freopen("Sliding Window.in","r",stdin);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        solve();
        for(int i=k;i<=n;i++) printf("%d ",mn[i]);
        printf("\n");
        for(int i=k;i<=n;i++) printf("%d ",mx[i]);
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    POJ 3260: The Fewest Coins
    题解链接 https://blog.csdn.net/u013480600/article/details/40617083
    以为需要单调队列来优化多重背包的,结果竟然直接过了。
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    题解链接 https://blog.csdn.net/u013480600/article/details/40617083
    以为需要单调队列来优化多重背包的,结果竟然直接过了。 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=100+5;
    const int maxm=10000+120*120+5; //maxt+maxv*maxv
    const int INF=0x3f3f3f3f;
    int n,t,v[maxn],c[maxn];
    int m,maxv=0,ans=INF;
    int d[maxm],f[maxm]; //d 支付 f 找零 
    void init(){
        memset(f,INF,sizeof(f));
        memset(d,INF,sizeof(d));
        f[0]=d[0]=0;
    }
    void dp1(){
        for(int i=1;i<=n;i++){
            if(v[i]*c[i]>=m) for(int j=v[i];j<=m;j++) d[j]=min(d[j],d[j-v[i]]+1);
            else{
                for(int j=m;j>=v[i];j--) for(int k=1;k<=c[i]&&j-k*v[i]>=0;k++) d[j]=min(d[j],d[j-k*v[i]]+k);
            }
        }
    }
    void dp2(){
        for(int i=1;i<=n;i++) for(int j=v[i];j<=m;j++) f[j]=min(f[j],f[j-v[i]]+1);
    }
    void solve(){
        for(int i=t;i<=m;i++) ans=min(ans,d[i]+f[i-t]);
    }
    int main() {
    //  ios::sync_with_stdio(false);
        //freopen("The Fewest Coins.in","r",stdin);
        scanf("%d%d",&n,&t);
        for(int i=1;i<=n;i++) scanf("%d",&v[i]),maxv=max(maxv,v[i]);
        for(int i=1;i<=n;i++) scanf("%d",&c[i]);
        m=t+maxv*maxv;
        init();
        dp1();
        dp2();
        solve();
        if(ans==INF) printf("-1");
        else printf("%d",ans);
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    POJ 1180: Batch Scheduling
    题解链接 https://www.jianshu.com/p/fdb41c13d11f
    代码如下

    /*
    
    */
    #define method_1
    #ifdef method_1
    /*
    题解链接 https://www.jianshu.com/p/fdb41c13d11f 
    */
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iomanip>
    #include<ctime>
    #include<string>
    #define D(x) cout<<#x<<" = "<<x<<"  "
    #define E cout<<endl
    using namespace std;
    typedef long long ll;
    typedef pair<int,int>pii;
    const int maxn=10000+5;
    const int INF=0x3f3f3f3f;
    int n,s,t[maxn],c[maxn];
    int q[maxn],f[maxn];
    void solve(){
        int l=1,r=1;
        f[0]=0;
        q[l]=0;
        for(int i=1;i<=n;i++){
            while(l<r&&(s+t[i])*(c[q[l+1]]-c[q[l]])>=f[q[l+1]]-f[q[l]]) l++;
            f[i]=f[q[l]]-(s+t[i])*c[q[l]]+t[i]*c[i]+s*c[n];//要使f[i]最小 就要f[j]最小 在截距一定的情况下 队首的斜率最小 所以结构也最小 
            while(l<r&&(f[i]-f[q[r]])*(c[q[r]]-c[q[r-1]])<=(f[q[r]]-f[q[r-1]])*(c[i]-c[q[r]])) r--;
            q[++r]=i;
        }
    }
    int main() {
        ios::sync_with_stdio(false);
        //freopen("Batch Scheduling.in","r",stdin);
        scanf("%d%d",&n,&s);
        for(int i=1;i<=n;i++) scanf("%d%d",&t[i],&c[i]),t[i]+=t[i-1],c[i]+=c[i-1];
        solve();
        printf("%d",f[n]);
        return 0;
    }
    #endif
    #ifdef method_2
    /*
    
    */
    
    #endif
    #ifdef method_3
    /*
    
    */
    
    #endif
    

    相关文章

      网友评论

          本文标题:常用技巧(二)

          本文链接:https://www.haomeiwen.com/subject/tdgauctx.html