Codeforces Round 856 (Div. 2)
《C. Scoring Subsequences》
这道题有很多解法:二分,双指针等,但是无论哪一种都要知道如下:
想要得到当k时,最大的分数,那么就会贪心地将后面的数相乘再除
设长度为len,那么在为k时,长度为len时,max score = (ak*a(k-1)*...*a(k-len+1)/len!
那么在len取何时,在score最大的情况下,len还是最长的?
这里暴力的话,将len枚举,再计算
但是会超时
想一下当len=m与len=m-1的区别
scoreM=(ak*a(k-1)*...*a(k-m+1)/m!
scoreM-1=(ak*a(k-1)*...*a(k-m+2)/(m-1)!
即scoreM-1比scoreM少乘了 a(k-m+1)/m
如果a(k-m+1)/m>1
scoreM-1>scoreM
反之
scoreM-1<scoreM
其余类推
用更数学的方式表示的话就是:
所以在k固定的情况下,对于选取len
即从len=k开始看到len=1,一旦a[k-len+1]/len<1
那么接下来的a[k-len+1]/len必定<1,即我们已经得到答案了
但是这样枚举还是会超时,这里提供两种方法
1.二分法:
二分枚举len,找到那个临界的len就是答案
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
void solve()
{
int n, a[100002];
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
int l = 1, r = i, ans = 0;
while (l <= r)
{
int mid = (l + r) >> 1;
if (a[i - mid + 1] / mid >= 1)
{
ans = mid;
l = mid + 1;
}
else
r = mid - 1;
}
cout << ans << " ";
}
cout << endl;
}
int main()
{
int t;
cin >> t;
while (t--)
solve();
return 0;
}
2.用queue:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
void solve()
{
int n, a[100002];
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
int cnt = 0;
queue<int> q;
for (int i = 1; i <= n; i++)
{
q.push(a[i]), cnt++;
while (q.size() != 0 && q.front() < cnt)
q.pop(), cnt--;
cout << cnt << " ";
}
cout << endl;
}
int main()
{
int t;
cin >> t;
while (t--)
solve();
return 0;
}