Codeforces 837F

837F - Prefix Sums

题意

定义函数 (p(x)) 会返回 (x) 这个数组的前缀和,定义 (A^i=p(A^{i-1}) (i > 0)),给出 (A^0) 求使得 (A^i) 中存在大于等于 (k) 的数的最小的 (i)

分析

打表容易发现当数的数量大于 (4) 时,直接暴力就很快。

关键就是数量有 (2)(3) 个时,怎么快速计算答案。

模拟一下发现,存在递推关系:

即第 (0) 项矩阵为

[egin{bmatrix} a_1 & a_2 & a_3 end{bmatrix} ]

那么第一项的矩阵为

[egin{bmatrix} a_1 & a_2 & a_3 end{bmatrix} * egin{bmatrix} 1 & 1 & 1\ 0 & 1 & 1\ 0 & 0 & 1 end{bmatrix}=egin{bmatrix} a_1 & a_1+a_2 & a_1+a_2+a_3 end{bmatrix} ]

后面类似,又显然存在单调性,可以使用二分求解。

这道题比较坑的就是会超 (long long) ,用了 (long double) 才能过,这种做法坑点有点多。

code

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 10;
const int N = 10;
typedef long long ll;
ll a[MAXN];
int n, cnt = 0;
ll K;
struct Matrix {
    long double mat[N][N];
    void init() {
        for(int i = 0; i < cnt; i++) {
            for(int j = 0; j < cnt; j++) {
                mat[i][j] = 0;
            }
        }
    }
};
Matrix operator * (Matrix A, Matrix B) {
    Matrix C;
    C.init();
    for(int i = 0; i < cnt; i++) {
        for(int j = 0; j < cnt; j++) {
            for(int k = 0; k < cnt; k++) {
                C.mat[i][j] += A.mat[i][k] * B.mat[k][j];
            }
        }
    }
    return C;
}
Matrix operator ^ (Matrix A, ll x) {
    Matrix B;
    B.init();
    for(int i = 0; i < cnt; i++) {
        for(int j = 0; j < cnt; j++) {
            if(i == j) B.mat[i][j] = 1;
        }
    }
    while(x) {
        if(x & 1) B = B * A;
        A = A * A;
        x >>= 1;
    }
    return B;
}
int judge(ll x) {
    Matrix A;
    A.init();
    for(int i = 0; i < cnt; i++) {
        for(int j = i; j < cnt; j++) {
            A.mat[i][j] = 1;
        }
    }
    A = A ^ x;
    Matrix B;
    B.init();
    for(int i = 0; i < cnt; i++) B.mat[0][i] = a[i + 1];
    B = B * A;
    for(int i = 0; i < cnt; i++) {
        if(B.mat[0][i] >= K) return 1;
    }
    return 0;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cin >> n >> K;
    for(int i = 0; i < n; i++) {
        ll x;
        cin >> x;
        if(!cnt && !x) continue;
        if(x >= 0) { a[++cnt] = x; }
        if(x >= K) {
            K = 0;
        }
    }
    ll ans = 0;
    if(K && cnt >= 4) {
        int flr = 1;
        while(1) {
            for(int i = 1; i <= cnt; i++) {
                a[i] += a[i - 1];
                if(a[i] >= K) {
                    ans = flr;
                    break;
                }
            }
            if(ans) break;
            flr++;
        }
    } else if(K) {
        ll l = 0, r = K;
        while(l < r) {
            ll mid = (l + r) / 2;
            if(judge(mid)) r = mid;
            else l = mid + 1;
        }
        ans = l;
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/ftae/p/7360444.html