[グループ] NOIオンライン最小のリングを向上させます

\(解決\)

我々はいくつかのリングにシーケンスを妨げることはありません。(これは、非干渉リングである\(K \)ではない、別の環の任意の場合)

実証することができる、我々は、に分割されます\(GCD(N、K) \) リング、各リングは持っている\(\ FRAC {N} { GCD(N、K)} \) 数多くの人々の問題に対する解決策はそう書かれているが、こんにゃくこんにゃくは、単純にこのことを理解していません

私たちは、それを証明しよう:

それがある場合はまず、リングは全体で同じでなければなりません。私たちは、各環が持っている設定\(X \)番号を。そして、そこにある:\(KX \ equiv0 \(MOD \ N-)\)

我々\(GCD(N、K) \) \(N- \)\(K \)次に、いくつかの小さな格子に分割されている\(\ FRAC {N} { GCD(N、K)} \) されています\(N \)いくつかのそのような小さなグリッドがあります。我々乗算それによって\(K \) 満足されなければならない(K \)\と散歩が達成可能であり、その後のために(N \)\、非常にある\(\ FRAC {N} { GCD(N、 K)} \)によって格子の小容量\(GCD(N、K) \) に拡張\(K \)合同の、また満足前述のニーズ。(あなたは小さなグリッド能力の前にしなければならないことに注意してください\(kは\)乗算を確保するように、要因です)

我々はそれを確実にしたい次は、各環が持っているということです\(\ FRAC {n}が{ GCD(n、k)は} \) 各リングは一度しか行くことができた回数を数えるために。(数自体は一度だけ表示されますので、実際には、この記述は、正確ではありません)

ので、この証明書は、実際には非常に良好である\(GCD \)の最大公約数であるので、\(\ FRAC {N} { GCD(N、K)} \) 、すなわち、最小である\(X \)

なぜ、兄を置くためにここに私を置くための証明である:神々を見るにはここをクリック

固定数の必須の答えは、我々はそれのメモリに従事、同じです。(要素の少数後に多くはありません)

コードを参照してください。

\(コード\)

#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N = 2e5 + 5;

ll a[N], memo[N], ans;
int n, m, k; 

int read() {
    int x = 0, f = 1; char s;
    while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
    return x * f;
}

int gcd(const int a, const int b) {
    if(! b) return a;
    return gcd(b, a % b);
}

int main() {
    n = read(), m = read();
    for(int i = 1; i <= n; ++ i) a[i] = read();
    sort(a + 1, a + n + 1);
    while(m --) {
        k = read();
        ans = 0;
        if(k == 0 || n == 1) {
            for(int i = 1; i <= n; ++ i) ans += a[i] * a[i];
            printf("%lld\n", ans);
            continue;
        }
        int t = gcd(n, k), per = n / t;
        if(memo[per]) {printf("%lld\n", memo[per]); continue;}
        for(int i = 1; i <= n; i += per) {
            for(int j = 0; j < per - 2; ++ j) ans += a[i + j] * a[i + j + 2];//按顺序取,相当是 min,min+2...min+3,min+1 (这是个环)
            ans += a[i] * a[i + 1] + a[i + per - 1] * a[i + per - 2];//取min与min+1,max与max-1
        }
        printf("%lld\n", ans);
        memo[per] = ans;
    }
    return 0;
} 

おすすめ

転載: www.cnblogs.com/AWhiteWall/p/12456259.html