• 7.24 校内模拟赛


    题目链接:【已去世】

    T1 送你一个DAG

    题目描述:给定一个DAG,求所有$1$到$i$的路径的长度的$k$次方之和$mathrm{mod} 998244353$.

    数据范围:$nleq 10^5,mleq 2*10^5,kleq 500$

    使用第二类斯特林数的通常幂转下降幂,可以转化为对于$i$求$sum inom{l}{j}$,其中$0leq jleq k$,使用组合数的递推公式$inom{n}{m}=inom{n-1}{m}+inom{n-1}{m-1}$可以dp计算。

    时间复杂度$O(mk)$。

     1 #include<bits/stdc++.h>
     2 #define Rint register int
     3 using namespace std;
     4 typedef long long LL;
     5 const int N = 100003, M = 200003, K = 503, mod = 998244353;
     6 int n, m, k, dp[N][K], fac[N], head[N], to[M], nxt[M], S[K][K];
     7 inline void add(int a, int b){
     8     static int cnt = 0;
     9     to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
    10 }
    11 inline void upd(int &a, int b){a += b; if(a >= mod) a -= mod;}
    12 int que[N], front, rear, d[N];
    13 int main(){
    14     scanf("%d%d%d", &n, &m, &k);
    15     for(Rint i = 1;i <= m;i ++){
    16         int u, v;
    17         scanf("%d%d", &u, &v);
    18         add(u, v); ++ d[v];
    19     }
    20     S[0][0] = 1;
    21     for(Rint i = 1;i <= k;i ++)
    22         for(Rint j = 1;j <= i;j ++)
    23             S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j]) % mod;
    24     fac[0] = 1;
    25     for(Rint i = 1;i <= k;i ++) fac[i] = 1ll * fac[i - 1] * i % mod;
    26     front = rear = 1;
    27     for(Rint i = 1;i <= n;i ++)
    28         if(!d[i]) que[rear ++] = i, dp[i][0] = 1;
    29     while(front < rear){
    30         int now = que[front ++];
    31         for(Rint i = head[now];i;i = nxt[i]){
    32             -- d[to[i]];
    33             if(!d[to[i]]) que[rear ++] = to[i];
    34             upd(dp[to[i]][0], dp[now][0]);
    35             for(Rint j = 1;j <= k;j ++){
    36                 upd(dp[to[i]][j], dp[now][j]);
    37                 upd(dp[to[i]][j], dp[now][j - 1]);
    38             }
    39         }
    40     }
    41     for(Rint i = 1;i <= n;i ++){
    42         int ans = 0;
    43         for(Rint j = 0;j <= k;j ++) upd(ans, 1ll * fac[j] * S[k][j] % mod * dp[i][j] % mod);
    44         printf("%d
    ", ans);
    45     }
    46 }
    T1

     1 #include<bits/stdc++.h>
     2 #define Rint register int
     3 using namespace std;
     4 typedef long long LL;
     5 const int N = 100003, M = 200003, K = 503, mod = 998244353;
     6 int n, m, k, dp[N][K], fac[N], head[N], to[M], nxt[M], S[K][K];
     7 inline void add(int a, int b){
     8     static int cnt = 0;
     9     to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
    10 }
    11 inline void upd(int &a, int b){a += b; if(a >= mod) a -= mod;}
    12 int que[N], front, rear, d[N];
    13 int main(){
    14     scanf("%d%d%d", &n, &m, &k);
    15     for(Rint i = 1;i <= m;i ++){
    16         int u, v;
    17         scanf("%d%d", &u, &v);
    18         add(u, v); ++ d[v];
    19     }
    20     S[0][0] = 1;
    21     for(Rint i = 1;i <= k;i ++)
    22         for(Rint j = 1;j <= i;j ++)
    23             S[i][j] = (S[i - 1][j - 1] + 1ll * j * S[i - 1][j]) % mod;
    24     fac[0] = 1;
    25     for(Rint i = 1;i <= k;i ++) fac[i] = 1ll * fac[i - 1] * i % mod;
    26     front = rear = 1;
    27     for(Rint i = 1;i <= n;i ++)
    28         if(!d[i]) que[rear ++] = i, dp[i][0] = 1;
    29     while(front < rear){
    30         int now = que[front ++];
    31         for(Rint i = head[now];i;i = nxt[i]){
    32             -- d[to[i]];
    33             if(!d[to[i]]) que[rear ++] = to[i];
    34             upd(dp[to[i]][0], dp[now][0]);
    35             for(Rint j = 1;j <= k;j ++){
    36                 upd(dp[to[i]][j], dp[now][j]);
    37                 upd(dp[to[i]][j], dp[now][j - 1]);
    38             }
    39         }
    40     }
    41     for(Rint i = 1;i <= n;i ++){
    42         int ans = 0;
    43         for(Rint j = 0;j <= k;j ++) upd(ans, 1ll * fac[j] * S[k][j] % mod * dp[i][j] % mod);
    44         printf("%d
    ", ans);
    45     }
    46 }T1

    T2 送你一棵圣诞树

    题目描述:给定一棵点带色的树,支持修改单点颜色,查询子树颜色在$[l,r]$中的数量(相同的只算一个),强制在线。

    数据范围:$n,c_ileq 10^5$。

    如果直接转化为在序列上做的话是一个四维偏序,时间复杂度高而且还有可能爆空间。

    所以有一个套路,对于每一种颜色的点,按照dfs序排序,将每个点打上+1,将每相邻两个点的lca打上-1,这样就可以做到相同的只算一个了。

    这里是注意到了子树相对于序列的区间多了一个条件,那就是询问的序列只有相离和包含关系,这样就可以去掉一维了。

    使用set维护每种颜色的点,用树状数组套动态开点线段树就可以在线做三维偏序了。

    hsz神仙说即使不知道这个技巧也可以使用$O(n^{frac{5}{3}})$的分块轻松跑过去(但是对于我来说就太难写了,膜膜膜)。

      1 #include<bits/stdc++.h>
      2 #define Rint register int
      3 using namespace std;
      4 const int N = 100003;
      5 int n, q, t, col[N], head[N], to[N << 1], nxt[N << 1], lastans;
      6 inline void add(int a, int b){
      7     static int cnt = 0;
      8     to[++ cnt] = b; nxt[cnt] = head[a]; head[a] = cnt;
      9 }
     10 int fa[N], wson[N], dep[N], siz[N];
     11 inline void dfs1(int x){
     12     siz[x] = 1;
     13     for(Rint i = head[x];i;i = nxt[i])
     14         if(to[i] != fa[x]){
     15             dep[to[i]] = dep[x] + 1;
     16             fa[to[i]] = x;
     17             dfs1(to[i]);
     18             siz[x] += siz[to[i]];
     19             if(siz[to[i]] > siz[wson[x]]) wson[x] = to[i];
     20         }
     21 }
     22 int dfn[N], pre[N], top[N], tim;
     23 inline void dfs2(int x, int topf){
     24     dfn[x] = ++ tim; pre[tim] = x; top[x] = topf;
     25     if(wson[x]) dfs2(wson[x], topf);
     26     for(Rint i = head[x];i;i = nxt[i])
     27         if(to[i] != fa[x] && to[i] != wson[x])
     28             dfs2(to[i], to[i]);
     29 }
     30 struct cmp {inline bool operator () (int a, int b){return dfn[a] < dfn[b];}};
     31 set<int, cmp> vec[N];
     32 inline int LCA(int u, int v){
     33     while(top[u] != top[v]){
     34         if(dep[top[u]] < dep[top[v]]) swap(u, v);
     35         u = fa[top[u]];
     36     }
     37     return dep[u] < dep[v] ? u : v;
     38 }
     39 int root[N], seg[N * 150], ls[N * 150], rs[N * 150], cnt;
     40 inline void change(int &x, int L, int R, int pos, int val){
     41     if(!x) x = ++ cnt; seg[x] += val;
     42     if(L == R) return;
     43     int mid = L + R >> 1;
     44     if(pos <= mid) change(ls[x], L, mid, pos, val);
     45     else change(rs[x], mid + 1, R, pos, val);
     46 }
     47 inline int query(int &x, int L, int R, int l, int r){
     48     if(!x || r < l) return 0;
     49     if(l <= L && R <= r) return seg[x];
     50     int mid = L + R >> 1, res = 0;
     51     if(l <= mid) res = query(ls[x], L, mid, l, r);
     52     if(mid < r) res += query(rs[x], mid + 1, R, l, r);
     53     return res;
     54 }
     55 inline int lowbit(int x){return x & -x;}
     56 inline void change(int posx, int posy, int val){
     57     while(posx <= n){
     58         change(root[posx], 1, n, posy, val);
     59         posx += lowbit(posx);
     60     }
     61 }
     62 inline int query(int posx, int l, int r){
     63     int res = 0;
     64     while(posx){
     65         res += query(root[posx], 1, n, l, r);
     66         posx -= lowbit(posx); 
     67     }
     68     return res;
     69 }
     70 int main(){
     71     scanf("%d%d%d", &n, &q, &t);
     72     for(Rint i = 1;i <= n;i ++)
     73         scanf("%d", col + i);
     74     for(Rint i = 1;i < n;i ++){
     75         int a, b;
     76         scanf("%d%d", &a, &b);
     77         add(a, b); add(b, a);
     78     }
     79     dfs1(1); dfs2(1, 1);
     80     for(Rint i = 1;i <= n;i ++) vec[col[i]].insert(i);
     81     for(Rint i = 1;i <= n;i ++)
     82         for(set<int, cmp> :: iterator it = vec[i].begin();it != vec[i].end();it ++){
     83             change(i, dfn[*it], 1);
     84             if(next(it) != vec[i].end()) change(i, dfn[LCA(*it, *next(it))], -1);
     85         }
     86     while(q --){
     87         int opt, u, x, y;
     88         scanf("%d%d%d", &opt, &u, &x);
     89         if(t) u ^= lastans, x ^= lastans;
     90         if(opt == 1){
     91             scanf("%d", &y); if(t) y ^= lastans;
     92             printf("%d
    ", lastans = query(y, dfn[u], dfn[u] + siz[u] - 1) - query(x - 1, dfn[u], dfn[u] + siz[u] - 1));
     93         } else {
     94             set<int, cmp> :: iterator it = vec[col[u]].find(u);
     95             change(col[u], dfn[u], -1);
     96             if(it != vec[col[u]].begin()) change(col[u], dfn[LCA(*it, *prev(it))], 1);
     97             if(next(it) != vec[col[u]].end()) change(col[u], dfn[LCA(*it, *next(it))], 1);
     98             if(it != vec[col[u]].begin() && next(it) != vec[col[u]].end())
     99                 change(col[u], dfn[LCA(*prev(it), *next(it))], -1);
    100             vec[col[u]].erase(it); col[u] = x;
    101             it = vec[x].insert(u).first;
    102             if(it != vec[x].begin()) change(x, dfn[LCA(*prev(it), *it)], -1);
    103             if(next(it) != vec[x].end()) change(x, dfn[LCA(*it, *next(it))], -1);
    104             if(it != vec[x].begin() && next(it) != vec[x].end())
    105                 change(x, dfn[LCA(*prev(it), *next(it))], 1);
    106             change(x, dfn[u], 1);
    107         }
    108     }
    109 }
    T2

    T3 送你一棵圣诞树

    神仙题,咕咕咕。。。

  • 相关阅读:
    SQL 数据库 复制 与订阅 实现数据同步
    SQL 2008配置管理工具服务显示 远程过程调用失败0x800706be
    SQL2005中使用identity_insert向自动增量字段中写入内
    【树莓派】【转载】基于树莓派,制作家庭媒体中心+下载机
    Linux 按时间批量删除文件(删除N天前文件)
    【树莓派】为树莓派配置或扩展swap分区
    开源硬件相关平台
    【树莓派】树莓派上刷android系统
    【树莓派】树莓派上面安装配置teamviewer
    【树莓派】使用xdrp远程登录树莓派的图形界面
  • 原文地址:https://www.cnblogs.com/AThousandMoons/p/11249711.html
Copyright © 2020-2023  润新知