Szybkie wczytywanie danych w C++ (Fast IO) przy pomocy scanf, oraz optymalizacja kodu

0

Witam, mam takie zadanko, http://pl.spoj.com/problems/BAJTIOS1/ moj program podaje prawidłowe wyniki, ale jest zbyt wolny algorytm i cały czas dostaję przekroczono czas na spoj, moje pytanie brzmi jak go usprawnić i zoptymalizować aby działał szybciej ? Jakieś fast IO czy coś w tym stylu?
Mój kod programu wygląda następująco, mam w nim cztery pętle for i myślę, że również przez nie program działa dużo wolniej:
Proszę o jakieś wskazówki dla początkującego :)

#include <vector>
#include <iostream>
#include <cstdio>
#include <cstdlib>

using namespace std;

/*
	n - liczba dni pomiarow
	m - liczba punktow pomiarowych
	p - srednie zanieczyszczenie

	q - liczba zapytan
	a - pierwszy dzien okresu pomiarowego
	b - ostatni dzien okresu pomiarowego
*/

int main() {
	std::ios_base::sync_with_stdio(0);
	int n;
	int q, a, b;
	double p, m, k;
	
	double suma;
	int liczba_dni_przekroczen = 0;
	string number;
	vector<double> srednie;
	
	scanf("%d %lf %lf", &n, &m, &p);
	k = 1 / m;
	for(int index = 0; index < n; ++index) {                                  // LOOP
		suma = 0.0;
		cin >> number;
		while(cin.get() != '\n'); 
		for(int index_punktow = 0; index_punktow < m; ++index_punktow) {      // LOOP
			string tmp = " ";
			tmp[0] = number[index_punktow];
			suma += atoi( tmp.c_str() );
		}
		srednie.push_back( suma * k ); // srednia pomiaru dla danego dnia ( mnozenie szybsze przez odwrotnosc m )
	}
	
	scanf("%d", &q);// liczba zapytan
	for(int index = 0; index < q; ++index) {                                  // LOOP
		scanf("%d %d", &a, &b);
		for(int i = a-1; i < b && i < srednie.size(); ++i) {                  // LOOP
			if(srednie[i] > p) liczba_dni_przekroczen += 1; 
		}
		printf("%d\n", liczba_dni_przekroczen);
	}
	return 0;
}
0

skoro używasz scanf to nie potrzebujesz tego: std::ios_base::sync_with_stdio(0);

set<unsigned> OverlapedDays;
for(int unsigned=1;day<=n;++day)
  {
   unsigned suma=0;
   getchar(); // enter z poprzedniego wczytywania
   for(unsigned i=0;i<m;++i) suma+=(getchar()-'0');
   if(suma>p*m) OverlapedDays.insert(day);
  }
0

Po modyfikacji kod aktualnie wygląda następująco, ale niestety dalej pokazuje "przekroczono czas" na spoj, ja już zwątpiłem:

#include <iostream>
#include <cstdio>
#include <set>

using namespace std;

/*
	n - liczba dni pomiarow
	m - liczba punktow pomiarowych
	p - srednie zanieczyszczenie

	q - liczba zapytan
	a - pierwszy dzien okresu pomiarowego
	b - ostatni dzien okresu pomiarowego
*/

int main() {
	int n;
	int q, a, b;
	double p, m;
	
	int liczba_dni_przekroczen = 0;
	
	scanf("%d %lf %lf", &n, &m, &p);
	
	set<unsigned> OverlapedDays;
	for(int unsigned day = 1; day <= n; ++day) {
		unsigned suma = 0;
		getchar(); // enter z poprzedniego wczytywania
		for(unsigned i = 0; i < m; ++i) 
			suma += (getchar() - '0');	
		if(suma > p * m) OverlapedDays.insert(day);
	}
	
	scanf("%d", &q);// liczba zapytan
	for(int index = 0; index < q; ++index) {                        
		scanf("%d %d", &a, &b);
		
		for(set<unsigned>::iterator it = OverlapedDays.begin(); it != OverlapedDays.end(); ++it) {
			if(*it >= a && *it <= b) ++liczba_dni_przekroczen;
		}
		
		printf("%d\n", liczba_dni_przekroczen);
		liczba_dni_przekroczen = 0;
	}
	
	return 0;
}
0

Jak masz "przekroczony czas" to przemyśl algorytm a nie kombinuj z szybkim I/O, bo guzik ci to da.

0

Algorytm działa poprawnie dla np:

1 20 2.000
11111111111111111111
1
1 1

odpowiedź: 0 
5 3 5.333
682
049
537
299
387
3
1 5
2 3
4 5 
odpowiedź:
3
0
2 
1 1 1.000
3
1
1 1 
odpowiedź: 1

1 1 1.000
1
1
1 1 
odpowiedź: 0

pytanie jest jakie spoj ma dane testowe, że się może on zapętlić.

0

@jackoi ale poprawność algorytmu nie ma tu nic do rzeczy.
Przykład: załóżmy że masz napisać program który liczy sumę zadanego ciągu arytmetycznego aż do zdefiniowanego wyrazu n. Optymalne rozwiązanie stosuje wzór na sumę częściową ciągu i wylicza wynik w czasie stałym, niezaleznym od n. Rozwiązanie równie poprawne z punktu widzenia wyniku, ale nieoptymalne, może na przykład w pętli dokonywać sumowania, dając wynik w czasie liniowym względem n.
Oba algorytmy dają poprawne wyniki, ale ten drugi dla dużych n będzie działał wolno.

1

Na SPOJ zadania poprawnie (optymalnie) rozwiązane, ale z nieoptymalnym IO, zawsze zmieszczą się w limicie czasowym.
Natomiast zadania z naiwnym algorytmem, ale z optymalizowanym IO zwykle nie przechodzą przez limit czasowy.
Żyłowanie operacji IO ma sens jedynie, jeśli ci zależy na wysokiej pozycji w rankingu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1