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か月あたりの日数のプレフィックスと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;
}
- 足を踏み入れる
一般的なアイデア、実際には前者は足を使ってアイデアをとるのに似ています---- l、rダブルポインター、現在の日数と<kがr ++の場合、月の終点を見つけることができ、次にl ++、lになるまで開始エンドポイントの月、つまり(sum-a [l] = a [l + 1] +…+ a [r] <kおよびsum> = k)で、プレフィックスを計算し、回答を計算します。 。
自分で書いたことがないのでコードはありませんが、CFにはたくさんあります。