codeforces Round#645(Div。2)D問題解決

Codeforces Round#645(Div。2)-D問題の解決策
ルーキーとして、もちろんAはありません。この問題のデータは小さすぎます。残念ながら、データカードは機能していません。
この質問の最も重要な点は、結論を出す必要があるということです。回答の最終日は月末でなければなりません。これにより、月末、月の初め、接頭辞、計算する日数を列挙できます。具体的には、2つのO(nlogn)またはO(n)に分けることができます
。結論の証明:
チュートリアルを参照し、矛盾する方法を使用します。最適なソリューションがあり、その最終日が月末ではないと仮定して、最適なソリューションの最終日の要素をx、次の日はx + 1であることがわかります(月末ではないため)。これが最適なソリューションであるため、旅行計画が1日遅れると、現在の回答と旅行計画よりも良い答えは得られません。 1日遅れるとは、最適解の左端の要素にx + 1を加えたものを引くことを意味します。したがって、左端の要素は> x + 1であることがわかります。したがって、左端の左にある1日の要素は> xであるため、次のことがわかります。 ———旅行計画を1日進めて、要素> xを追加し、xを減算すると、矛盾した最適な解決策よりも答えが優れていることがわかります。
特定の写真を組み合わせることができます:

完全なアプローチ:

  1. 二分法+プレフィックス合計
    1か月あたりの日数のプレフィックスとx、および1か月あたりの抱擁数と配列yのプレフィックスを前処理します。
    毎月の最終日を列挙します。つまり、x [i]> = kごとに、upper_boundを使用してx> x [i] -kの最初の添え字jを見つけます(この場合、iは月末を表します) 、Jは最初の段落の月を表します)プレフィックスとy配列を使用して、2つのエンドポイント間の抱擁の数を計算します(y [i] -y [j-1])。このとき、抱擁数の一部はjのために計算されることに注意してください。月にはエンドポイントのみが含まれるため、x配列を使用して、月jの日数を計算し(x [i] -x [j-1] -k)、その日数の抱擁の数を回答から差し引きます。これは(t *(t +1)/ 2)コーディングでき
    ます:
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define ll long long 
ll x[400005];
ll y[400005];
ll z[400005];
int main()
{
    
    
    ll n, m;
    cin >> n >> m;
    int i;
    for (i = 0; i < n; i++)
    {
    
    
        scanf("%d", &x[i]);
        x[i + n] = x[i];
    }
    n = n * 2;
    for (i = 0; i < n; i++)
    {
    
    
        if (i)
        {
    
    
            y[i] = x[i] + y[i - 1];
            z[i] = x[i] * (x[i] + 1) / 2 + z[i - 1];
        }
        else
        {
    
    
            y[i] = x[i];
            z[i] = x[i] * (x[i] + 1);
        }
    }
    ll ma = 0;
    for (i = 0; i < n; i++)
    {
    
    
        if (y[i] >= m)
        {
    
    
            int pos = upper_bound(y, y + n, y[i] - m) - y;
            ll ans = z[i] - z[pos];
            ll days = y[i] - (pos==0?0:y[pos-1]);
            ll cha = days - m;
            
            ans = ans - (cha) * (cha + 1) / 2 + (x[pos]) * (x[pos] + 1) / 2;
            //cout << cha << endl;
            ma = max(ma, ans);
        }
    }
    cout << ma << endl;
}
  1. 足を踏み入れる
    一般的なアイデア、実際には前者は足を使ってアイデアをとるのに似ています---- l、rダブルポインター、現在の日数と<kがr ++の場合、月の終点を見つけることができ、次にl ++、lになるまで開始エンドポイントの月、つまり(sum-a [l] = a [l + 1] +…+ a [r] <kおよびsum> = k)で、プレフィックスを計算し、回答を計算します。 。
    自分で書いたことがないのでコードはありませんが、CFにはたくさんあります。

おすすめ

転載: blog.csdn.net/ylwhxht/article/details/106390289