NOI Online#1レイズグループT3ミニマムリング

オリジナルタイトルリンク

簡潔なタイトル:

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

おすすめ

転載: blog.csdn.net/weixin_44043668/article/details/108808511
おすすめ