オリジナルタイトルリンク
簡潔なタイトル:
距離kkが与えられた場合、リングには数字がありますk、∑ i = 1 n(ai×ai + k)\ sum ^ {n} _ {i = 1}(a_i \ times a_ {i + k})となるようなシーケンスを作成します∑i = 1n個(A私××AI + K)最大。これは、リングでの加算と減算を指します。
分析:
この質問の戦略を考えるのは簡単で、2つの大きなものを乗算する方が明らかに費用効果が高くなります。だから私は考えることができます1 11開始bfsbfsb f s、左右の数字を拡大し、大きいものから小さいものへと数字を入れます。しかし、これは問題を起こしやすいです:いくつかは決して見つかりません!たとえば、タイトルのサンプル、k = 3 k = 3k=3つのケースの半分は検索できません。解決策があります:tarjantarjanのようにすべてのビットをマークしますt a r j a nと同じように、各ポイントでマークを探し、マークなしで検索します。このメソッドの時間の複雑さは、Θ(n)\ Theta(n)です。Θ (n )、動作しますが、試していません。試験中に考えたのですが、時間が足りなかったので書きませんでした。簡潔なコード方法について話しましょう。
上記の問題を見つけることは難しくないので、各検索をグループに分けることができます。グループにはいくつありますか?つまり、n÷gcd(n、k)n \ div gcd(n、k)n÷g c d (n 、k )個 私はこれを証明しません、それは純粋に一つずつ試してみるパターンです。コメント欄にそれを証明してくれる巨人がいたら、付け加えて感謝します。したがって、多くのグループに分割する方が簡単です。各グループは互いに干渉せず、前のbfsbfsに従ってb f sメソッドは、グループ内の数値が連続していることを発見しました。グループ内で、最大と2番目に大きい、最小と2番目に小さいの乗算を除いて、このグループ内のすべてがai + 2×aia_ {i + 2} \ times a_ {i}であることを見つけるのは難しくありません。AI + 2××A私の。ズームインの便宜のために、ここにaaがあることに注意してくださいaはすでに最大から最小にソートされています。だから、私たちは毎回iiすることもできますiにグループの数を加えたもの。これはaaと同等です。前者のサブグループの一部。時間の複雑さもΘ(n)\ Theta(n)Θ (n )。
上記の2つの方法では、多くのkkが存在するため、時間の複雑さはまだ十分ではありません。k要件。しかし、そのkkを見つけましたkがある未満N÷2 N \ DIV2n÷2、つまり1 0 5 10 ^ 51 05種類のKKk要件ですが、1 05×210 ^ 5 \ times21 05××2 Gekkk。それぞれを個別に要求する場合は、TLE TLET L Eいくつかのポイント。ただし、リクエストの数は種の数よりもはるかに多く、多くの繰り返しが必要です。だからあなたはffを使うことができますf配列は各kkを格納しますkの答え、繰り返される直接出力に遭遇しました。しかし、今回はまだ非常にタイトで、グループが同じグループに分けられている限り、答えは同じであることがわかります。はるかに少ないkkを出力できますk、最初の方法を最適化するには、数値のグループも必要であることに注意してください。
合計時間の複雑さΘ(kn)\ Theta(kn)Θ (k n )。
コード:
#include<bits/stdc++.h>
using namespace std;
const int NN=2e5+4;
long long a[NN],f[NN];
int gcd(int a,int b)
{
return !b?a:gcd(b,a%b);
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
while(m--)
{
int k;
scanf("%d",&k);
long long ans=0;
if(k==0||n==1)
{
if(f[0])
{
printf("%lld\n",f[0]);
continue;
}
for(int i=1;i<=n;i++)
ans+=a[i]*a[i];
f[0]=ans;
printf("%lld\n",ans);
continue;
}
int team=n/gcd(n,k);
if(f[team])
{
printf("%lld\n",f[team]);
continue;
}
for(int i=1;i<=n;i+=team)
{
for(int j=0;j<team-2;j++)
ans+=a[i+j]*a[i+j+2];
ans+=(a[i]*a[i+1]+a[i+team-1]*a[i+team-2]);
}
f[team]=ans;
printf("%lld\n",ans);
}
return 0;
}