Сканирование, метод двух указателей
Поиск подпоследовательности с максимальной суммой можно выполнить за время `O(N^3)`, перебирая все комбинации начала и конца этой последовательности и вычисляя сумму. Если предварительно вычислить частичные суммы, то время уменьшится до `O(N^2)`. Но существует простой алгоритм, работающий за `O(N)` и основанный на следующей идее. Если подпоследовательность имеет неотрицательную сумму элементов, то её выгодно включить в максимальную подпоследовательность. Т.е. можно рассматривать подпоследовательность в качестве составной части искомой подпоследовательности, пока сумма её элементов неотрицательна.
int maxseq(int a[], int n, int &i1, int &i2)
{ int i, i0=0, s=0, ms=0;
i1=0;
i2=-1;
for(i=0; i<n; ++i)
{
s+=a[i];
if(s<0)
{ i0=i+1; //
s=0;
}
else if(ms<s) //
{ i1=i0;
i2=i;
ms=s;
}
}
return ms;
}
Длина прямой, покрытой отрезками, вычисляется с помощью сканирования – движения вдоль прямой, по точкам изменения состояния. В данном случае такими точками являются левые и правые концы отрезков. Эти точки нужно отсортировать по координатам. Если часть прямой между предыдущей и очередной точкой покрыта хотя бы одним отрезком, то его длину нужно добавить к суммарной длине покрытия.
int n; //
pair<int,int> o[30000];
cin>>n;
for(int i=0;i<n;++i)
{ int l,r;
cin>>l>>r;
o[i*2].first=l;
o[i*2].second=1; //
o[i*2+1].first=r;
o[i*2+1].second=-1; //
}
sort(o,o+2*n);
int x=-100000000, //
k=0, //
p=0; //
for(int i=0;i<2*n;++i)
{
int d=o[i].first-x; //
if(k>0) p+=d;
k+=o[i].second;
x=o[i].first;
}
cout<<p<<"\n";
Метод двух указателей применяется, если мы должны найти координаты левого и правого конца отрезка, в котором некоторая вычисляемая величина имеет заданное значение. Если значение величины меньше заданной, то мы должны увеличивать правый указатель (индекс); если больше заданной, то увеличиваем левый указатель (индекс); если совпадает с заданной, то обрабатываем найденный отрезок и увеличиваем левый указатель (индекс).
Найти подстроку минимальной длины, содержащую ровно `n` символов 'A'.
const int INF=1e9;
int l=0,r=-1,
lmin=0,rmin=INF,k=0,n;
char s[1000000];
cin>>n>>s;
while(1)
{ if(k<n)
{ ++r;
if(s[r]=='\0') break; //
k+=s[r]=='A';
}
else {
if(k==n && rmin-lmin>r-l) { lmin=l; rmin=r; }
k-=s[l++]=='A';
}
}
if(rmin!=INF)
cout<<lmin<<' '<<rmin<<'\n';
else
cout<<"No\n";