南外集训Day4

前六题

一场前面巨简单,后面巨难的比赛。

第一题基础循环;第二题排序;第三题前缀后缀和/前后缀最小值,在这类问题中的套路是左括号视为1,右括号0,那么前缀和就可以知道数量差;第四题排序+set。至于第五题,单调栈板子,自己想了一种线段树扫描线的写法。

第六题考试时没想到能不卡时限过的做法,最后搞了一种3^n的做法,考试时给他跑过了,老师说正解就是这个……似乎是因为这个OJ跑得起飞。

上面是场切的题,以下是两题没切掉的题。


G题

题目

$$ F_{i+1}*(i+1)^k=F_{i-1}*(i+1)^k+F_i*(i+1)^k $$$$ =F_{i-1}*((i-1)+2)^k+F_i*((i)+1)^k $$ 用二项式定理展开:$$ \sum_{j=0}^k (C_k^j * 2^{k-j}) [F_{i-1}*(i-1)^j] + \sum_{j=0}^k C_k^j*(F_i*i^j) $$ 然后构造矩阵即可。

比如 $k=3$ 时的矩阵:

矩阵记录 $S_i$ 、 $F_i*i^0$ ~ $F_i*i^k$ 、 $F_{i+1}*i^0$ ~ $F_i*{i+1}^k$ 。

这道题做不出来纯属正常。时间复杂度 $O(k^3logn)$

#include <bits/stdc++.h>
#define ll long long
#define L(i, a, b) for (int i = a; i <= b; i++)
#define R(i, a, b) for (int i = a; i >= b; i--)
using namespace std;
const int N = 90;
const ll mod = 1e9 + 7;
struct Matrix {
    int n, m;
    ll a[N][N];
    Matrix(int r, int c, ll v = 0) : n(r), m(c) {
        L(i, 0, n) L(j, 0, m) a[i][j] = ((i == j) ? v : 0);
    }
    Matrix operator*(const Matrix x) const {
        Matrix res(n, x.m);
        L(i, 0, n){
            L(j, 0, x.m){
                L(k, 0, m){
                    res.a[i][j] = (res.a[i][j] + a[i][k] * x.a[k][j] % mod) % mod;
                }
            }
        }
        return res;
    }
    Matrix operator^(ll x) const {
        Matrix res(n, m, 1), a = *this;
        while (x) {
            if (x & 1)
                res = res * a;
            a = a * a;
            x >>= 1;
        }
        return res;
    }
};
ll n, p[N];
int k;
int main() {
    scanf("%lld%d", &n, &k);
    if (n == 1) {//特判情况
        puts("1");
        return 0;
    }
    Matrix x(2 * k + 2, 2 * k + 2), y(2 * k + 2, 0);
    p[0] = 1;
    L(i, 1, k + 1) p[i] = (p[i - 1] << 1) % mod;
    x.a[0][0] = 1;
    L(i, 0, k + 1) x.a[i + 1][k + i + 2] = 1;
    L(i, 0, k + 1) {
        L(j, 0, i) {
            if (!(i | j))
                x.a[k + 2][k + 2] = 1;//如果i和j都为0那么是初始值所以是特殊情况。
            else
                x.a[k + i + 2][k + j + 2] = (x.a[k + i + 1][k + j + 1] + x.a[k + i + 1][k + j + 2]) % mod;//构造右下的杨辉三角
            x.a[k + i + 2][j + 1] = 1ll * x.a[k + i + 2][k + j + 2] * p[i - j] % mod;//构造左下的矩阵
        }
    }
    L(i, 1, 2 * k + 2) x.a[0][i] = x.a[2 * k + 2][i];//这里和上面微有不同,因为这里是把i的值直接算进S,那样少算一步
    y.a[0][0] = y.a[1][0] = 1;
    L(i, 0, k + 1) y.a[k + i + 2][0] = 1;
    x = x ^ (n - 1);
    printf("%lld\n", (x * y).a[0][0]);
    return 0;
}

H题

题目

这道题非常简单,但是我脑抽了,硬是没想出来。

这道题用到最基础的补集思想。就是我们一看数据范围:啊,Meet in the mid+状压!!!

我们考虑模型转换,我们把相邻点建边,那样可以发现模型就变为用最小的代价使得每条边都有一个端点被选到。

我们考虑预处理出右边的每个状态对应的左边必须选的状态即权值和,然后枚举左边的状态,如果合法,那么把他的权值加上预处理的权值。

eazy!!!

posted @ 2023-01-17 08:29  徐子洋  阅读(54)  评论(0)    收藏  举报  来源