5.28 题解

A

转化成 ij=1n[sum(j)=i]

枚举 i,数位 DP 算 j=1n[sum(j)=i] 即可。

#include <cstdio>
#include <cstring>
#define M 10000007
int c, k, a[150];long long n, q = 1, f[150][150];
long long F(int x, int y, bool l)
{
    if(!x) return y == k;
    if(!l && ~f[x][y]) return f[x][y];long long q = 0;
    for(int i = 0, j = l ? a[x] : 1;i <= j;++i)
        q += F(x - 1, y + i, l && i == j);
    if(!l) f[x][y] = q;return q;
}
long long G(long long n)
{
    memset(f, -1, sizeof f);c = 0;
    while(n) a[++c] = n & 1, n >>= 1;
    return F(c, 0, 1);
}
long long P(long long x, long long y)
{
    long long q = 1;
    for(;y;y >>= 1, x = x * x % M)
        if(y & 1) q = q * x % M;
    return q;
}
int main()
{
//  freopen("a.in", "r", stdin);
//  freopen("a.out", "w", stdout);
    scanf("%lld", &n);
    for(k = 1;k <= 65;++k)
        q = q * P(k, G(n)) % M;
    printf("%lld", q);
    fclose(stdin);fclose(stdout);
    return 0;
}

B

不会。

C

整体二分套二维树状数组。

令询问 (x1,y1,x2,y2,k,s,t) 表示 (x1,y1)(x2,y2)[s,t] 内的第 k 小。

考虑对某组 s,t 处理所有询问 (x1,y1,x2,y2,k,s,t),设 m=s+t2

ai,j[s,m],令 ci,jci,j+1。然后对询问 (x1,y1,x2,y2,k,s,t)

i=x1x2j=y1y2ci,jk 则其答案等于 (x1,y1,x2,y2,k,s,m) 的答案,

否则其答案等于 (x1,y1,x2,y2,ki=x1x2j=y1y2ci,j,m+1,t) 的答案。

还原 c 数组,递归处理所有 (x1,y1,x2,y2,k,s,m) 的询问和 (x1,y1,x2,y2,k,m+1,t) 的询问。

二维树状数组维护 c

#include <cstdio>
struct S{int o, l1, l2, r1, r2, k, i;}a[500050], q1[500050], q2[500050];
int n, q, m, z[500050], c[550][550];
void M(int x, int y, int k)
{
    for(;x <= n;x += x & -x)
        for(int i = y;i <= n;i += i & -i)
            c[x][i] += k;
}
int Q(int x, int y)
{
    int q = 0;
    for(;x;x &= x - 1)
        for(int i = y;i;i &= i - 1)
            q += c[x][i];
    return q;
}
void D(int l, int r, int s, int t)
{
    if(l > r) return;
    if(s == t)
    {
        for(int i = l;i <= r;++i)
            if(a[i].o == 2) z[a[i].i] = s;
        return;
    }
    int m = s + t >> 1, c1 = 0, c2 = 0;
    for(int i = l, o;i <= r;++i)
    {
        if(a[i].o & 1)
        {
            if(a[i].k <= m)
                M(a[i].l1, a[i].l2, 1), q1[++c1] = a[i];
            else
                q2[++c2] = a[i];
        }
        else
        {
            o = Q(a[i].r1, a[i].r2) - Q(a[i].l1 - 1, a[i].r2) - Q(a[i].r1, a[i].l2 - 1) + Q(a[i].l1 - 1, a[i].l2 - 1);
            if(o >= a[i].k)
                q1[++c1] = a[i];
            else
                a[i].k -= o, q2[++c2] = a[i];
        }
    }
    for(int i = 1;i <= c1;++i) if(q1[i].o & 1) M(q1[i].l1, q1[i].l2, -1);
    for(int i = 1;i <= c1;++i) a[l + i - 1] = q1[i];
    for(int i = 1;i <= c2;++i) a[l + c1 + i - 1] = q2[i];
    D(l, l + c1 - 1, s, m);D(l + c1, r, m + 1, t);
}
int main()
{
//  freopen("c.in", "r", stdin);
//  freopen("c.out", "w", stdout);
    scanf("%d%d", &n, &q);
    for(int i = 1;i <= n;++i)
        for(int j = 1;j <= n;++j)
            a[++m] = (S){1, i, j, 0, 0, 0, 0}, scanf("%d", &a[m].k);
    for(int i = 1;i <= q;++i)
        a[++m] = (S){2, 0, 0, 0, 0, 0, i}, scanf("%d%d%d%d%d", &a[m].l1, &a[m].l2, &a[m].r1, &a[m].r2, &a[m].k);
    D(1, m, 1, 1e9);
    for(int i = 1;i <= q;++i)
        printf("%d\n", z[i]);
    return 0;
}

D

虚树 DP。

回收路径树就是最短路树,直接建出来。

具体地,以 K 为源跑 Dijkstra,然后每个点向其最短路上的前驱连边。

tx 表示 x 是否投放区域,修改操作直接取反。

被标记的区域就是以回收区域为关键点集建的虚树,每次询问直接建出来。

具体地,把关键点集按 DFS 序排序,然后关键点集与其相邻每两项的 LCA 即为标记区域,

标记区域之间按原树祖先关系连边,边权为原树上两点间边权和。

在建出的虚树上跑 DP。设 fx 表示阻碍 x 子树内所有投放区域的代价,则有

fu=vsonu{w(u,v)tv=1min(w(u,v),fv)tv=0

#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define P pair<int, int>
using namespace std;
const int N = 1e9;
struct G
{
    struct E{int v, w, t;}e[200050];int c, h[50050];
    void A(int u, int v, int w) {e[++c] = (E){v, w, h[u]};h[u] = c;}
}A, T, V;
bool t[50050], e[50050];P r[50050];
int n, m, s, p, O, a[50050], z[50050], b[50050], d[50050], f[50050][20], g[50050], W[50050], o[50050];
priority_queue<P, vector<P>, greater<P> > q;
bool C(int x, int y) {return b[x] < b[y];}
void D(int u)
{
    b[u] = ++p;
    for(int i = T.h[u], v;i;i = T.e[i].t)
    {
        d[v = T.e[i].v] = d[u] + 1;
        W[v] = W[f[v][0] = u] + T.e[i].w;
        for(int j = 1;f[v][j - 1];++j)
            f[v][j] = f[f[v][j - 1]][j - 1];D(v);
    }
}
int L(int x, int y)
{
    if(d[x] < d[y]) swap(x, y);
    while(d[x] > d[y]) x = f[x][__lg(d[x] - d[y])];
    if(x == y) return x;
    for(int k = __lg(d[x]);k >= 0;--k)
        if(f[x][k] != f[y][k]) x = f[x][k], y = f[y][k];
    return f[x][0];
}
void F(int u)
{
    o[u] = 0;
    for(int i = V.h[u], v;i;i = V.e[i].t)
        F(v = V.e[i].v), o[u] += min(V.e[i].w, t[v] ? N : o[v]);
}
int main()
{
//  freopen("d.in", "r", stdin);
//  freopen("d.out", "w", stdout);
    scanf("%d%d%d%d", &n, &m, &s, &O);
    for(int i = 0, u, v, w;i < m;++i)
        scanf("%d%d%d", &u, &v, &w), A.A(u, v, w), A.A(v, u, w);
    memset(g, 0x3f, sizeof g);q.push(P(g[s] = 0, s));
    while(!q.empty())
    {
        int u = q.top().second;q.pop();
        if(!e[u])
        {
            e[u] = 1;
            for(int i = A.h[u], v;i;i = A.e[i].t)
                if(g[v = A.e[i].v] > g[u] + A.e[i].w || g[v] == g[u] + A.e[i].w && r[v].first > u)
                    q.push(P(g[v] = g[r[v].first = u] + A.e[i].w, v)), r[v].second = A.e[i].w;
        }
    }
    for(int i = 1;i <= n;++i) if(r[i].first) T.A(r[i].first, i, r[i].second);D(s);
    for(int i = 0, r, k, c = 0;i < O;++i)
    {
        scanf("%d%d", &r, &k);
        if(r)
        {
            for(int j = 0;j < c;++j) V.h[z[j]] = 0;V.c = c = 0;
            for(int j = 0;j < k;++j) scanf("%d", a + j);a[k++] = s;sort(a, a + k, C);z[c++] = a[0];
            for(int j = 1;j < k;++j) z[c++] = L(a[j], a[j - 1]), z[c++] = a[j];sort(z, z + c, C);c = unique(z, z + c) - z;
            for(int j = 1, l;j < c;++j) l = L(z[j], z[j - 1]), V.A(l, z[j], W[z[j]] - W[l]);bool U = 1;
            for(int j = 0;j < c;++j) if(t[z[j]]) {U = 0;break;}if(U) {puts("-1");continue;}
            F(z[0]);printf("%d\n", o[z[0]]);
        }
        else
        {
            for(int j = 0, x;j < k;++j)
                scanf("%d", &x), t[x] ^= 1;
        }
    }
    return 0;
}

无返回值函数必须是 void 型的

posted @   Jijidawang  阅读(2)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示