2016-12-27 spoj MINSUB 二分,单调栈 spoj INTSUB 思维
题意:给定一个由非负数组成的矩阵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\n", ans1, check(ans1)); } return 0; }
题意:给定一个集合,该集合由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\n", cas, (ans+mod)%mod); } return 0; }