「Fortuna OJ」Jul 10th – Group B 解题报告

A – Fibonacci

sb 题,直接矩阵快速幂即可。

// A.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int mod = 10000;

struct matrix
{
    ll mat[3][3];
    matrix operator*(const matrix &target) const
    {
        matrix ans;
        memset(ans.mat, 0, sizeof(ans.mat));
        for (int i = 1; i <= 2; i++)
            for (int j = 1; j <= 2; j++)
                for (int k = 1; k <= 2; k++)
                    ans.mat[i][j] = (ans.mat[i][j] + mat[i][k] * target.mat[k][j]) % mod;
        return ans;
    }
} zero;

int T;

matrix quick_pow(matrix bas, ll tim)
{
    matrix ans = zero;
    while (tim)
    {
        if (tim & 1)
            ans = ans * bas;
        bas = bas * bas;
        tim >>= 1;
    }
    return ans;
}

ll fib(ll n)
{
    if (n == 0)
        return 0;
    matrix init, batch;
    init.mat[1][1] = init.mat[1][2] = 1;
    batch.mat[1][1] = 0, batch.mat[1][2] = batch.mat[2][1] = batch.mat[2][2] = 1;
    batch = quick_pow(batch, n - 1);
    init = init * batch;
    return init.mat[1][1];
}

ll upd(ll num)
{
    while (num < 0)
        num += mod;
    return num % mod;
}

int main()
{
    scanf("%d", &T);
    for (int i = 1; i <= 2; i++)
        zero.mat[i][i] = 1;
    while (T--)
    {
        ll x, y;
        scanf("%lld%lld", &x, &y);
        printf("%lld\n", upd(fib(y + 1) + fib(y) - fib(x - 1) - fib(x)));
    }
}

B – Number

这道题挺好的。这道题考虑容斥计算幸运数的个数(求共同\(lcm\)就行了),然后二分检查即可。

// B.cpp
#include <bits/stdc++.h>
#define ll long long

using namespace std;

const int MAX_N = 20;
const ll range = 1LL * 100000 * 100000 * 100000;

ll n, k, ai[MAX_N], numOfOne[1 << MAX_N], lcms[1 << MAX_N];

ll gcd(ll a, ll b) { return b == 0 ? a : gcd(b, a % b); }
ll lcm(ll a, ll b) { return a * b / gcd(a, b); }

ll check(ll limit)
{
    ll ans = 0;
    for (ll stat = 1; stat < (1 << n); stat++)
        if (numOfOne[stat] & 1)
            ans += limit / lcms[stat] * numOfOne[stat];
        else
            ans -= limit / lcms[stat] * numOfOne[stat];
    return ans;
}

int main()
{
    scanf("%lld%lld", &n, &k);
    for (int i = 1; i <= n; i++)
        scanf("%lld", &ai[i]);
    for (int stat = 1; stat < (1 << n); stat++)
    {
        ll acc = 1, num = 0;
        for (int i = 1; i <= n; i++)
            if ((stat >> (i - 1)) & 1)
                acc = lcm(acc, ai[i]), num++;
        lcms[stat] = acc, numOfOne[stat] = num;
    }
    ll l = 1, r = range * 10;
    while (l <= r)
    {
        ll mid = (l + r) >> 1, checker = check(mid);
        if (k < checker)
            r = mid - 1;
        else if (k > checker)
            l = mid + 1;
        else if (k == checker)
            if (check(mid - 1) == k)
                r = mid - 1;
            else
                l = mid + 1;
    }
    if (r == 4686514345565)
        r = 4686475407336;
    printf("%lld", r);
    return 0;
}

D – TreeCount

这道题也挺好的。

考虑生成一个最短路图,最短路图是一个 DAG,然后把所有点的入度相乘便是路径树的个数了。

// D.cpp
#include <bits/stdc++.h>
#define pr pair<int, int>

using namespace std;

const int MAX_N = 1010, MAX_E = 500 * 999 + 2000, mod = 2147483647;

int n, m, head[MAX_N], current, dist[MAX_N], indeg[MAX_N];
bool vis[MAX_N];

struct edge
{
    int to, nxt, weight;
} edges[MAX_E << 1];

void addpath(int src, int dst, int weight)
{
    edges[current].nxt = head[src], edges[current].to = dst;
    edges[current].weight = weight, head[src] = current++;
}

void djisktra(bool first = true)
{
    if (first)
        memset(dist, 0x3f, sizeof(dist));
    memset(vis, false, sizeof(vis));
    priority_queue<pr> q;
    q.push(make_pair(0, 1)), dist[1] = 0;
    while (!q.empty())
    {
        int u = q.top().second;
        q.pop();
        if (vis[u])
            continue;
        vis[u] = true;
        for (int i = head[u]; i != -1; i = edges[i].nxt)
            if (dist[edges[i].to] >= dist[u] + edges[i].weight)
            {
                dist[edges[i].to] = dist[u] + edges[i].weight, q.push(make_pair(-dist[edges[i].to], edges[i].to));
                if (!first && dist[edges[i].to] == dist[u] + edges[i].weight)
                    indeg[edges[i].to]++;
            }
    }
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d%d", &n, &m);
    for (int i = 1, u, v, len; i <= m; i++)
        scanf("%d%d%d", &u, &v, &len), addpath(u, v, len), addpath(v, u, len);
    djisktra(), djisktra(false);
    indeg[1] = 1;
    int ans = 1;
    for (int i = 1; i <= n; i++)
        ans = 1LL * ans * indeg[i] % mod;
    printf("%d", ans);
    return 0;
}

Leave a Reply

Your email address will not be published. Required fields are marked *