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;
}

 

 

     

 

 

posted @ 2023-03-05 20:02  次林梦叶  阅读(133)  评论(0)    收藏  举报