ksum及二维版本
Peter喜欢玩数组。NOIP这天,他从Jason手里得到了大小为n的一个正整数数组。Peter求出了这个数组的所有子段
和,并将这n(n+1)/2个数降序排序,他想知道前k个数是什么。
输入
第一行包含两个整数 n 和 k。
接下来一行包含 n 个正整数,代表数组。
ai≤109 k≤n(n+1)/2,n≤100000,k≤100000
输出
输出 k 个数,代表降序之后的前 k 个数,每个数字后面有一个空格
样例输入 Copy
3 4
1 3 4
样例输出 Copy
8 7 4 4
Sol:
这个题我们只知道最大的和是所有数字加起来,因为都是正数嘛。
但第二大,第三大并不知道。
而且并不是数列长度越长,总和越大。
例如
9 1 1 1 1
第1个数字就为9,但后面的四个数字的和才为4。
所以下面这个程序是错的
#include <bits/stdc++.h> using namespace std; int n, k, i, a[100010]; long long sum[111010]; priority_queue<long long>q; int main() { scanf("%d%d", &n, &k); int tot = 0; for (i = 1; i <= n; i++) scanf("%d", a + i), sum[i] = sum[i - 1] + a[i]; for (int len = n ; len >= 1; len--) { for (int i = 1; i <= n + 1 - len; i++) { int j = i + len - 1; long long tt = sum[j] - sum[i - 1]; q.push(tt); tot++; } if (tot >= 2*k) //数据太水了,居然放过了 break; } while (k) { cout << q.top() << " "; q.pop(); k--; } }
于是我们可以将最大的数字放入堆中,而并不是拘泥于数列的长度。
然后尝试将其变小,因为是连续数字和,所以要么去掉最左边的,要么去掉最右边的。将得到的新的数列再放入堆中,让它们去比大小。
当然这个操作要进行判重。
于是对下这种数据
5 5
9 1 1 1 1
我们就能跑出正常的结果了。
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> using namespace std; struct node{ int l,r; long long s; }t,z; int n,k,a[100010]; long long s; priority_queue<node> q; bool operator <(node a,node b){ return a.s<b.s; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); s+=a[i]; } t.s=s; t.l=1; t.r=n; q.push(t); for(int i=1;i<=k;i++) { t=q.top(); q.pop(); printf("%lld ",t.s); z.l=t.l; z.r=t.r-1; z.s=t.s-a[t.r]; q.push(z); if(t.r==n) { z.l=t.l+1; z.r=t.r; z.s=t.s-a[t.l]; q.push(z); } } return 0; }
https://www.cnblogs.com/GXZlegend/p/7816312.html
【bzoj4165】矩阵 堆+STL-map
定义和谐矩阵为长不小于 Mina 且宽不小于 Minb 的矩阵,矩阵的权值为整个矩阵内所有数的和。给定一个长为 N,宽为 M 的矩阵 A,求它的所有和谐子矩阵中权值第 K 小的矩阵,并输出它的权值。
输入
第 1 行为五个正整数,分别为 N , M , Mina , Minb , K,相邻两个数用一个空格分隔。接下来的 N 行,每行 M
个用一个空格分隔的数,表示给定的矩阵 A。
1 <= N,M <=1000, 1 <= Mina <= N, 1 <= Minb <= M,
1 <= K <= 250000 ,矩阵 A 内每个数均为不超过 3000 的非负整数
输出
仅一行,一个数,表示第 K 小矩阵的权值。如果第 K 小矩阵不存在,输出-1。
样例输入
3 4 2 2 3
0 1 3 7
1 16 5 2
7 6 9 3
样例输出
19
堆+STL-map
这种类型的题也没少做了,初次写这样的大概是 [NOI2010]超级钢琴 。
由于所有元素非负,因此一个矩形的权值和一定比其任意一个子矩形权值和大。因此只有在处理完子矩形后才处理该矩形。
使用堆维护贪心顺序,初始时把所有长度为Mina,宽度为Minb的矩形加入堆中,每次取堆顶元素,并把该举行左、右、上、下扩展一层所得的矩形加入堆中。
然而这样矩形会计算重复,因此需要使用hash表储存一个矩形是否出现过。
我使用了map,由于常数巨大而垫底...
时间复杂度 O(nm+klogk)
#include <set> #include <queue> #include <cstdio> #include <cctype> #include <cstring> #define N 1010 using namespace std; typedef pair<int , int> pr; typedef long long ll; ll sum[N][N]; struct data { int a , b , c , d; data() {} data(int w , int x , int y , int z) {a = w , b = x , c = y , d = z;} bool operator<(const data &x)const {return a == x.a ? b == x.b ? c == x.c ? d < x.d : c < x.c : b < x.b : a < x.a;} ll query()const {return sum[c][d] - sum[c][b - 1] - sum[a - 1][d] + sum[a - 1][b - 1];} }; struct cmp { bool operator()(const data &x , const data &y) { return x.query() > y.query(); } }; priority_queue<data , vector<data> , cmp> heap; set<data> s; inline char nc() { static char buf[100000] , *p1 , *p2; return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ; } inline int read() { int ret = 0; char ch = nc(); while(!isdigit(ch)) ch = nc(); while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc(); return ret; } int main() { int n = read() , m = read() , p = read() , q = read() , k = read() , i , j; ll ans = 0; data t , tmp; for(i = 1 ; i <= n ; i ++ ) for(j = 1 ; j <= m ; j ++ ) sum[i][j] = read() + sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1]; for(i = 1 ; i <= n - p + 1 ; i ++ ) for(j = 1 ; j <= m - q + 1 ; j ++ ) t = data(i , j , i + p - 1 , j + q - 1) , heap.push(t) , s.insert(t); for(i = 1 ; i <= k ; i ++ ) { if(heap.empty()) { puts("-1"); return 0; } t = heap.top() , heap.pop() , ans = t.query(); if(t.a > 1 && s.find(tmp = data(t.a - 1 , t.b , t.c , t.d)) == s.end()) heap.push(tmp) , s.insert(tmp); if(t.b > 1 && s.find(tmp = data(t.a , t.b - 1 , t.c , t.d)) == s.end()) heap.push(tmp) , s.insert(tmp); if(t.c < n && s.find(tmp = data(t.a , t.b , t.c + 1 , t.d)) == s.end()) heap.push(tmp) , s.insert(tmp); if(t.d < m && s.find(tmp = data(t.a , t.b , t.c , t.d + 1)) == s.end()) heap.push(tmp) , s.insert(tmp); } printf("%lld\n" , ans); return 0; }