01/10/2018, 12:26

Giúp đỡ bài tập: Tìm đoạn dài nhất có tổng dương

cho mình hỏi bài này làm như thế nào với ạ.mình nghĩ gần 1 tháng rồi mà vẫn không ra ạ

HK boy viết 14:34 ngày 01/10/2018

Dùng tổng cộng dồn.

Định nghĩa s[0] = 0, s[i] = a[1] + a[2] + ... + a[i] = s[i-1] + a[i].

-> Tổng các số trong đoạn l, r = a[l] + a[l+1] + ... + a[r] = s[r] - s[l-1]

-> Tổng các số trong đoạn l, r dương <-> s[r] > s[l-1].

từ từ để nghĩ tiếp…

Trần Hoàn viết 14:42 ngày 01/10/2018

Tìm đoạn dương có chiều dài n, nếu có in ra, kết thúc
Nếu không có, tìm đoạn dương có chiều dài n - 1, nếu có in ra, kết thúc
Nếu không có, tìm đoạn dương có chiều dài n - 2, nếu có in ra, kết thúc
…
Nếu không có, tìm đoạn dương có chiều dài 1, nếu có in ra, kết thúc
Nếu không có, trả lời, kết thúc

HK boy viết 14:39 ngày 01/10/2018

Em nghĩ thuật này dễ bị quá thời gian.

Trần Hoàn viết 14:42 ngày 01/10/2018

Chuyện đó tính sau. Đề bài đâu có giới hạn thời gian

HK boy viết 14:41 ngày 01/10/2018

Đề bài đâu có giới hạn thời gian

Thế thôi, cứ O(n^2) mà quất.

Ideone.com

Ideone.com

Ideone is something more than a pastebin; it's an online compiler and debugging tool which allows to compile and run code online in more than 40 programming languages.

Gió viết 14:35 ngày 01/10/2018

Có thể tìm được trong O(nlogn)
giả sử tính được mảng cộng dồn s[i] = sum(a[0:i])
dùng 2 mảng phụ tmp, index để tính đoạn dài nhất: mảng tmp này là mảng giảm

  • Nếu s[i] < tmp.back(): trước đó không có phần tử nào nhỏ hơn: cập nhật thêm vào tmp, cập nhật i vào mảng index(để tính độ dài)
  • Nếu không ta tìm phần tử nhỏ hơn đứng trước của s[i] trong tmp, và sử dụng index để tính xem nó có phải là kết quả tốt nhất không. Ở bước này, s[i] không được thêm vào nữa bởi vì nếu có tmp[j]<s[i] thì đoạn tmp[j] < s[i] <s[k] sẽ dài hơn.
#include <iostream>
#include <algorithm>
#include <limits>
#include <vector>

using namespace std;


int main() {
	
	int n;
	cin>>n;
	vector<int> a(n);
	for(int i=0;i<n;i++){
		cin>>a[i];
	}
	
	vector<int> tmp;
	vector<int> index;
	
	int s = 0;
	int best = 0;
	int L = 0;
	int H = 0;
	tmp.push_back(0);
	index.push_back(0);
	for(int i=0;i<n;i++) {
		s+=a[i];
		if(s<tmp.back()) {
			tmp.push_back(s);
			index.push_back(i+1);
		}else{
			if(s == tmp.back()) continue;
			auto it = upper_bound(tmp.begin(),tmp.end(),s,greater<int>());
		
			int index_tmp = distance(tmp.begin(),it);
			
			int base_array_index = index[index_tmp];
			
			if(i+1 - base_array_index>=best ) {
				best = i - base_array_index+1;
				L = base_array_index+1;
				H = i+1;
			}
			
		}
	}
	cout<<L<<" "<<H<<endl;
	
	return 0;
}
Hieu Hoang viết 14:42 ngày 01/10/2018
public class a {

int n= 100;
int[] A= new int[n];
int v= n*(n+1)/2;
int[]tong= new int[v];
int[]length= new int[v];
int count = 0;
int max;
for (iint i=0;i<tong.length ;i++ ) {
	tong[i]=0;
}
for (int i=0;i<A.length-1 ;i++ ) {
	for (int j=i+1;j<A.length ;j++ ) {
		for (int k=i;k<=j ;k++ ) {
			tong[count]+=A[k];
		}
		length[count]=j-i+1;
		count++;
	}
}
max=0;
for (int i=0;i<tong.length ;i++ ) {
	if (tong[i]>0) {
		if (length[i]>max) {
			max=length[i];
		}
	}
}
}

mình mới học nên làm kiểu thủ công: tạo 1 dãy chứa tổng và 1 dãy chưa độ dài các tập con trong chứa các phần tử liên tiếp của mảng A. A có n phần tử thì 2 dãy kia có n(n+1)/2 phần tử. Sau đó duyệt tong[i]>0 để kiếm max của length

Nguyễn Đình Biển viết 14:28 ngày 01/10/2018

Bài này dùng cây BIT/IT để lấy và cập nhật :v

nắng viết 14:27 ngày 01/10/2018

bạn ơi bài này có thuật o(n) không vậy

HK boy viết 14:41 ngày 01/10/2018

Thuật O(n log n) khá ổn rồi, O(n) thì quá khó để thực hiện. Mà limit bài này là n = 60000 nên O(n log n) vẫn chạy tốt, cần gì phải O(n).

gnodhn viết 14:36 ngày 01/10/2018

Bạn có thể dùng BIT or IT để làm. Với IT(x) là vị trí nhỏ nhất có tổng lớn nhỏ hoặc bằng x update thì khi tới vị trí i có tổng là K thì update từ âm vô cùng đến K , với tổng k đó thì mình querý từ âm vô cùng đến K . NlogN

HK boy viết 14:33 ngày 01/10/2018

Thuật có chắc chắn đúng không bạn? Và bạn có chứng minh được thuật của bạn chỉ là O(n) hay không?

Tùng Vux viết 14:40 ngày 01/10/2018

Chủ thớt có thể ghi lại đề bài được ko ? Ko hiểu sao ko thể load được ảnh …

rogp10 viết 14:28 ngày 01/10/2018

Cho a[1…n] thỏa n <= 60000 và abs(a[i]) <= 10000, đặt sum_ij = a[i] + a[i+1] + … + a[j]. Trong các (j, i) để sum_ij > 0, cực đại j - i.

Bài liên quan
0