zoukankan      html  css  js  c++  java
  • 2016-12-27 spoj MINSUB 二分,单调栈 spoj INTSUB 思维

    每日链接题解

    spoj  MINSUB   

    题意:给定一个由非负数组成的矩阵M,和一个整数K,对于矩阵M的子矩阵M’,定义min(M’)为M'矩阵中元素的最小值。我们需要找出这样一个子矩阵,该矩阵的面积至少为K,且min(M’)最大化。面积的定义为该矩阵的行数*列数。

    tags: 好题      首先想到二分最小值mx,但check(mx)该怎么写呢? 可以简化为01矩阵,然后check(mx)就是要求出最大的全1子矩阵的面积,这个最大全1子矩阵面积(1000*1000)怎么求呢?这里是关键。  先统计出每个位置向左最多有多少个连续的1,然后对于每一列,就是要求出每列中以每个数为最小数的区间,类似于poj 2796

    这类问题都是可以二分答案的。把小于二分值的位置设为0,其他设为1,那么问题就变成了求全为1的子矩阵的最大面积,这件事情可以用单调栈搞(方法类似于传送门,事先统计出每个位置向左有多少个1)。

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 1005;
    
    int n, m, k, a[N][N], b[N][N], top;
    struct Point {int ai, l, r; }sta[N*2];
    int calc(int cj)
    {
        top=0;
        int ans=0, l;
        sta[++top]=(Point){b[1][cj], 1, 1 };
        rep(i,2,n)
        {
            l=i;
            while(top>0 && sta[top].ai>=b[i][cj]) {
                if(top-1>0) sta[top-1].r=sta[top].r;
                int area= sta[top].ai*(sta[top].r-sta[top].l+1);
                ans=max(ans, area);
                l=sta[top].l;
                --top;
            }
            sta[++top]=(Point){b[i][cj], l, i };
        }
        while(top>0) {
            if(top-1>0) sta[top-1].r=sta[top].r;
            int area= sta[top].ai*(sta[top].r-sta[top].l+1);
            ans=max(ans, area);
            --top;
        }
        return ans;
    }
    int check(int x)
    {
        rep(i,1,n)  rep(j,1,m)
            if(a[i][j]>=x) b[i][j]=b[i][j-1]+1;
            else b[i][j]=0;
        int ans=0;
        rep(j,1,m) ans=max(ans, calc(j));
        return ans;
    }
    int main()
    {
        int T;  scanf("%d", &T);
        while(T--)
        {
            scanf("%d %d %d", &n, &m, &k);
            rep(i,1,n) rep(j,1,m) scanf("%d", &a[i][j]);
            int l=0, r=1e9, ans1, mid;
            while(l<=r) {
                mid=(l+r)>>1;
                if(check(mid)>=k) l=mid+1, ans1=mid;
                else  r=mid-1;
            }
            printf("%d %d
    ", ans1, check(ans1));
        }
    
        return 0;
    }
    View Code

    spoj  INTSUB

    题意:给定一个集合,该集合由1,2,3....2n组成,n是一个整数。问该集合中有趣子集的数目,答案mod1e9+7。x的子集合有趣定义为,该子集中至少有两个数,a和b,b是a的倍数且a是集合中最小的元素。

    tags:一开始真没想到枚举最小元素,MDZZ

    枚举子集中最小的元素,然后确定其他的元素。   假设现在最小元素为a,则有2n/a-1个大于a的元素是a的倍数,且这些元素必须在子集中出现至少一个,剩下的大于a的数取和不取对答案不造成影响。    累计不同的a对答案的贡献即可。

    #include<bits/stdc++.h>
    using namespace std;
    #pragma comment(linker, "/STACK:102400000,102400000")
    #define rep(i,a,b) for (int i=a;i<=b;i++)
    #define per(i,b,a) for (int i=b;i>=a;i--)
    #define mes(a,b)  memset(a,b,sizeof(a))
    #define INF 0x3f3f3f3f
    typedef long long ll;
    const int N = 200005,  mod=1000000007;
    
    ll  fpow(ll a, int b) {ll ans=1; for(; b; a=a*a%mod, b>>=1) if(b&1) ans=ans*a%mod; return ans; }
    int main()
    {
        int T;  scanf("%d", &T);
        rep(cas,1,T)
        {
            int n;  scanf("%d", &n);
            ll ans=0;
            rep(i,1,2*n) {
                int x=2*n/i-1, y=2*n-i-x;
                ans = (ans+ (fpow(2,x)-1)*fpow(2,y)%mod);
            }
            printf("Case %d: %lld
    ", cas, (ans+mod)%mod);
        }
    
        return 0;
    }
    View Code
  • 相关阅读:
    tcprstat分析服务的响应速度
    mysqldump之不老将
    Java数据持久层框架 MyBatis之API学习二(入门)
    Java数据持久层框架 MyBatis之API学习一(简介)
    插入数据库日期格式转换
    eclipse出现错误:he type java.util.Map$Entry cannot be resolved. It is indirectly referenced
    注释中不允许出现字符串 "--"。
    mybatis if条件查询 及<号的问题
    This is probably because there is no OLE editor registered against the type of file you were trying to open.
    github not authorized eclipse
  • 原文地址:https://www.cnblogs.com/sbfhy/p/6741101.html
Copyright © 2011-2022 走看看