牛客OI赛制测试赛

昨天晚上打了一场很水很水的比赛,题目没有什么思维难度,总结一下经验吧:

_MistY

A

发现了一个结论:令斐波那契数列的 f ( 1 ) = f ( 2 ) = 1 ,则有

f ( n 1 ) f ( n + 1 ) f ( n ) 2 = { 1 , n  &  1 = 0 1 , n  &  1 = 1

利用归纳法证明:

首先, n = 2 时肯定是符合的,有 f ( k 1 ) f ( k + 1 ) f ( k ) 2 = ( 1 ) k ,那么我们只需要证明 n = k + 1 时也符合。

(6) f ( k ) f ( k + 2 ) f ( k + 1 ) 2 = f ( k ) 2 + f ( k ) f ( k + 1 ) f ( k 1 ) 2 2 f ( k 1 ) f ( k ) f ( k ) 2 (7) = f ( k ) 2 + f ( k 1 ) f ( k ) f ( k 1 ) 2 2 f ( k 1 ) f ( k ) (8) = f ( k ) 2 f ( k 1 ) 2 f ( k 1 ) f ( k ) (9) = f ( k ) 2 f ( k 1 ) f ( k + 1 ) (10) = ( 1 ) k + 1

于是再来看看 西 ……

卡西尼恒等式: f ( n 1 ) f ( n + 1 ) f ( n ) 2 = ( 1 ) n

但这个东西真的是对的吗?

经过验证后,这个悖论明显是错的,因为右图的两个三角形并不相似:一个是 5 : 13 ,一个是 3 : 8

(学妹还剪纸验证了一下,拼不起来233)

C

数据随机……暴力可过。

E

最长不下降子序列的二分函数中, l 应该从 0 开始,
因为如果序列中没有小于等于 x 的数, x 应该放在 l + 1 = 1 的位置。

int find(int x) {
    int l = 0, r = len;
    while (l < r) {
        int mid = l + (r - l + 1 >> 1);
        if (d[mid] <= x) l = mid;
        else r = mid - 1;
    }
    return l;
}

F

题目大意:给出一个长度为 n 的序列,你需要计算出所有长度为 k 的子序列中,除最大最小数之外所有数的乘积相乘的结果,答案对 1 e 9 + 7 取模。

很显然将原序列从小到大排好序后,答案应该为

i = 2 n 1 a i ( n 1 k 1 ) ( i 1 k 1 ) ( n i k 1 )

但指数不可以直接取模,考虑模数是一个质数,有

而当 p 不是质数的时候,我们有

a b { a b mod φ ( p ) , a p a ( b mod φ ( p ) ) + φ ( p ) , b φ ( p ) a b , b < φ ( p ) ( mod p )

——扩展欧拉定理

考虑如何证明 a ( b mod φ ( p ) ) + φ ( p )   ( b φ ( p ) ) ,我们有

{ x y ( mod m 1 ) x y ( mod m 2 ) x y ( mod m n ) x y ( mod l c m { m 1 , m 2 , , m n } )

其中 m 1 m 2 m n

假设模数 m = p k (素数的幂), b φ ( m ) ,显然 φ ( m ) k

( a , p ) = 1 ,那么 a m ,所以

a b a ( b mod φ ( m ) ) + φ ( m ) ( mod m )

( a , p ) = p ,则 a = λ p ,显然 a b a ( b mod φ ( m ) ) + φ ( m ) 的指数均大于等于 k ,所以

a b 0 a ( b mod φ ( m ) ) + φ ( m ) ( mod m )

对于任意模数,均可唯一分解成若干素数的乘积,根据最上面的同余方程组可知, a ( b mod φ ( p ) ) + φ ( p )   ( b φ ( p ) ) 对任意 p 成立。

#include <cstdio>
#include <algorithm>

const int N = 1005, P = 1000000007;
int C[N][N], a[N];

int read() {
    int x = 0, f = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') f = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        x = (x << 3) + (x << 1) + (c ^ 48);
        c = getchar();
    }
    return x * f;
}
void pre() {
    C[0][0] = 1;
    for (int i = 1; i <= 1000; ++i) {
        C[i][0] = 1;
        for (int j = 1; j <= i; ++j)
            C[i][j] = (C[i-1][j] + C[i-1][j-1]) % (P - 1);
    }
}
int pow(int a, int b) {
    int res = 1;
    for (; b; b >>= 1, a = 1LL * a * a % P)
        if (b & 1) res = 1LL * res * a % P;
    return res;
}

int main() {
    pre();
    int T = read();
    while (T--) {
        int n = read(), k = read(), ans = 1;
        for (int i = 1; i <= n; ++i) a[i] = read();
        if (n < 3) { puts("0"); continue; }
        std::sort(a + 1, a + n + 1);
        for (int i = 2; i < n; ++i) {
            ans = 1LL * ans * pow(a[i], ((C[n-1][k-1] - C[i-1][k-1] - C[n-i][k-1]) % (P - 1) + (P - 1)) % (P - 1)) % P;
        }
        printf("%d\n", (ans + P) % P);
    }
    return 0;
}

时间复杂度 O ( n l o g n )

猜你喜欢

转载自blog.csdn.net/Milkyyyyy/article/details/82216128