zoukankan      html  css  js  c++  java
  • CCPC-Wannafly Winter Camp Day8 (Div2, onsite)

    Replay


    Dup4:

    • 厕所是个换换脑子的好地方?
    • 要读题啊,不要别人不做,自己就跟着不做啊

     X:

    • 读题很重要啊!什么时候才能读对题 不演队友啊 D题看错题, 直到最后一小时才看懂
    • 很多时候要看榜单做题

    A:Aqours

    Solved.

    考虑一个点的子树下面有多少个叶子节点汇聚,

    那么这个时候就可以更新某些叶子节点的答案

    并且把距离该点最近的叶子节点返回上去继续做这一步操作

    再正着  考虑除子树外 的离当前点最近的叶子节点的距离,用于更新子树中叶子结点的答案

    相当于树形dp起手式

    但是这里$n很大,不能DFS$

    但是又注意到$i <= j  有 fa[i] < fa[j]$

    相当于$bfs序列是1;2;cdots n$

    可以直接两次遍历来做这件事情

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 3000010
     5 #define pii pair <int, int>
     6 int n, fa[N], ans[N], d[N];   
     7 vector <pii> G[N];
     8 pii g[N];
     9 
    10 int main()
    11 {
    12     while (scanf("%d", &n) != EOF)
    13     {
    14         for (int i = 1; i <= n; ++i) G[i].clear();
    15         memset(ans, -1, sizeof ans);
    16         memset(d, 0, sizeof d);
    17         fa[1] = 0; 
    18         for (int i = 2; i <= n; ++i)
    19         {
    20             scanf("%d", fa + i);
    21             ++d[fa[i]];
    22         }    
    23         for (int v = n; v >= 1; --v)
    24         {
    25             int u = fa[v];
    26             if (!d[v]) 
    27                 G[u].push_back(pii(v, 1)); 
    28             else
    29             {
    30                 sort(G[v].begin(), G[v].end());
    31                 pii tmp = *G[v].begin();
    32                 ++tmp.second;
    33                 G[u].push_back(tmp);
    34                 int Min = (*G[v].begin()).second;
    35                 for (int i = 1, len = G[v].size(); i < len; ++i)
    36                 {
    37                     pii it = G[v][i];
    38                     ans[it.first] = Min + it.second;
    39                 }
    40             }
    41         }
    42         for (int v = 1; v <= n; ++v)
    43         {
    44             g[v] = pii(1e9, 1e9);
    45             int u = fa[v];
    46             if (u)
    47             {
    48                 g[v] = g[u];
    49                 ++g[v].second;
    50                 pii tmp = g[v];
    51                 if (tmp.first != -1) for (int i = 0, len = G[v].size(); i < len; ++i) 
    52                 {
    53                     pii it = G[v][i];
    54                     if (it.first > tmp.first)    
    55                         ans[it.first] = min(ans[it.first], it.second + tmp.second);  
    56                 }
    57             }
    58             if (!G[v].empty())
    59             {
    60                 pii it = *G[v].begin();
    61                 if (it.second < g[v].second)
    62                     g[v] = it;
    63             }
    64         }
    65         for (int i = 1; i <= n; ++i) if (!d[i]) printf("%d %d
    ", i, ans[i]); 
    66     }
    67     return 0;
    68 }
    View Code

    B:玖凛两开花

    Upsolved.

    我们可以发现,如果答案是$x,那么小于等于x的点的都要匹配到大于等于x的点$

    那么我们把$小于x的点放在左边,大于等于x的点放在右边,二分匹配即可$

    这样就有一个二分的做法

    但实际上一步一步枚举上去也是可行的,$枚举到x + 1的时候,拆掉x + 1原有的匹配关系,再匹配一次即可$

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define N 10010
     5 int n, m, l, r;
     6 vector <int> G[N]; 
     7 
     8 int linker[N];
     9 bool used[N];
    10 bool DFS(int u)
    11 {
    12     for (auto v : G[u]) if (v >= l && v <= r && !used[v])
    13     {
    14         used[v] = true;
    15         if (linker[v] == -1 || DFS(linker[v]))
    16         {
    17             linker[v] = u;
    18             return true; 
    19         }
    20     }
    21     return false;
    22 }
    23 
    24 int main()
    25 {
    26     while (scanf("%d%d", &n, &m) != EOF)
    27     {
    28         for (int i = 1; i <= n; ++i) G[i].clear();
    29         for (int i = 1, u, v; i <= m; ++i) 
    30         {
    31             scanf("%d%d", &u, &v);
    32             G[u].push_back(v);
    33             G[v].push_back(u);
    34         }
    35         int res = 0;
    36         memset(linker, -1, sizeof linker); 
    37         for (int i = 0; i < n - 1; ++i) 
    38         {
    39             l = i + 1, r = n - 1; 
    40             if (linker[i] != -1)
    41             {
    42                 memset(used, 0, sizeof used);
    43                 if (!DFS(linker[i])) break;
    44                 linker[i] = -1;
    45             }
    46             memset(used, 0, sizeof used);
    47             if (DFS(i)) ++res;
    48             else break;
    49         }
    50         printf("%d
    ", res);
    51     }
    52     return 0;
    53 }
    View Code

    D:吉良吉影的奇妙计划

    Solved.

    n只有20

    暴力打表

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 const int maxn = 110;
     7 const ll MOD = 998244353;
     8 
     9 
    10 int n;
    11 ll ans = 0;
    12 int arr[maxn];
    13 int tmp[maxn];
    14 
    15 bool judge()
    16 {
    17     for(int i = 1; i <= 2 * n; ++i) tmp[i] = arr[i];
    18     int flag = 1;
    19     while(flag)
    20     {
    21         flag = 0;
    22         for(int i = 1; i + 1 <= 2 * n; ++i)
    23         {
    24             if((tmp[i] == 1 && tmp[i + 1] == 0) || (tmp[i] == 0 && tmp[i + 1] == 1)) 
    25             {
    26                 tmp[i] = tmp[i + 1] = -1;
    27                 flag = 1;
    28                 break;
    29             }
    30         }
    31     }
    32     for(int i = 1; i + 3 <= 2 * n; ++i)
    33     {
    34         if(tmp[i] + tmp[i + 1] + tmp[i + 2] + tmp[i + 3] == -4) return true;
    35     }
    36     return false;
    37 }
    38 
    39 void DFS(int cnt, int cnt1, int cnt0)
    40 {
    41     if(cnt == 2 * n + 1)
    42     {
    43         ans = (ans + 1) % MOD;
    44         return ;
    45     }
    46     if(cnt1)
    47     {
    48         if(cnt == 1 || (cnt > 1 && arr[cnt - 1] != 0))
    49         {
    50             arr[cnt] = 1;
    51             DFS(cnt + 1, cnt1 - 1, cnt0);
    52         }
    53     }
    54     if(cnt0)
    55     {
    56         if(cnt == 1 || (cnt > 1 && arr[cnt - 1] != 1))
    57         {
    58             arr[cnt] = 0;
    59             DFS(cnt + 1, cnt1, cnt0 - 1);
    60         }
    61     }
    62     if(cnt1 > 0 && cnt0 > 0)
    63     {
    64         if((cnt + 1 <= 2 * n && arr[cnt - 1] != -1))
    65         {
    66             arr[cnt] = -1;
    67             arr[cnt + 1] = -1;
    68             DFS(cnt + 2, cnt1 - 1, cnt0 - 1);
    69             arr[cnt] = -2;
    70             arr[cnt + 1] = -2;
    71         }
    72     }
    73 }
    74 
    75 int main()
    76 {
    77     while(~scanf("%d", &n))
    78     {
    79         ans = 0;
    80         DFS(1, n, n);
    81         cout << ans << endl;
    82     }
    83     return 0;
    84 }
    View Code

    E:Souls-like Game

    Solved.

    阅读理解题

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 10010
     6 const ll MOD = (ll)998244353;
     7 int n, m, p[N][3][3];
     8 
     9 int main()
    10 {
    11     while (scanf("%d%d", &n, &m) != EOF)
    12     {
    13         for (int i = 1; i < n; ++i)
    14         {
    15             for (int j = 0; j < 3; ++j)
    16                 for (int k = 0; k < 3; ++k)
    17                     scanf("%d", &p[i][j][k]), p[i][j][k] %= MOD;
    18         }
    19         for (int i = 1, op, l, r; i <= m; ++i)
    20         {
    21             scanf("%d%d%d", &op, &l, &r);
    22             if (op == 1) 
    23             {
    24                 int pp[3][3]; 
    25                 for (int j = 0; j < 3; ++j) 
    26                     for (int k = 0; k < 3; ++k) 
    27                         scanf("%d", &pp[j][k]), pp[j][k] %= MOD;
    28                 for (int j = l; j <= r; ++j)
    29                     for (int k = 0; k < 3; ++k)
    30                         for (int o = 0; o < 3; ++o)
    31                             p[j][k][o] = pp[k][o];
    32             }
    33             else
    34             {
    35                 ll sum[2][3] = {0, 0, 0};
    36                 for (int j = 0; j < 3; ++j) sum[r & 1][j] = 1;
    37                 for (int j = r - 1; j >= l; --j)
    38                 {
    39                     for (int k = 0; k < 3; ++k) sum[j & 1][k] = 0;
    40                     for (int k = 0; k < 3; ++k)
    41                         for (int o = 0; o < 3; ++o)
    42                             sum[j & 1][k] = (sum[j & 1][k] + p[j][k][o] * sum[(j & 1) ^ 1][o] % MOD) % MOD;
    43                 }
    44                 ll res = 0;
    45                 for (int j = 0; j < 3; ++j) 
    46                     res = (res + sum[l & 1][j]) % MOD;
    47                 //for (int j = 0; j < 3; ++j) printf("%lld%c", sum[l & 1][j], " 
    "[j == 2]);
    48                 printf("%lld
    ", res);
    49             }
    50         }
    51     }
    52     return 0;
    53 }
    View Code

    G:穗乃果的考试

    Solved.

    $考虑到每个(i, j)位置上的1可能被i cdot (n - i + 1) cdot j cdot (m - j + 1)的矩形包含$

    $即每个1都会产生i cdot (n - i + 1) cdot j cdot (m - j + 1)的贡献 累加即可$

     1 #include<bits/stdc++.h>
     2 
     3 using namespace std;
     4 
     5 typedef long long ll;
     6 
     7 const ll MOD = 998244353;
     8 const int maxn = 2e3 + 10;
     9 
    10 int n, m;
    11 char mp[maxn][maxn];
    12 
    13 int main()
    14 {
    15     while(~scanf("%d %d", &n, &m))
    16     {
    17         ll ans = 0;
    18         for(int i = 1; i <= n; ++i)
    19         {
    20             for(int j = 1; j <= m; ++j)
    21             {
    22                 scanf(" %c", &mp[i][j]);
    23                 if(mp[i][j] == '1')
    24                 {
    25                     ll tmp = i * (n - i + 1) % MOD * j % MOD * (m - j + 1) % MOD;
    26                     ans = (ans + tmp) % MOD;
    27                 }
    28             }
    29         }
    30         printf("%lld
    ", ans);
    31     }
    32     return 0;
    33 }
    View Code

    I:岸边露伴的人生经验

    Upsolved.

    将十维的向量拆成二十位的二进制数

    可以通过FWT快速的卷积以下,得到异或后相同的对数

    为了方便,我们将距离平方

    再将异或值转换成距离

    这里注意$dis(1, 2) = 1, 而 1 oplus 2 = 3$ 

    $dis(0, 2) = 4, 0 oplus 2 = 2$

    然后统计即可

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 #define ll long long
     5 #define N 2500010
     6 const ll MOD = (ll)998244353; 
     7 const ll inv_2 = (ll)499122177;
     8 int n;
     9 ll c[N];
    10 ll a[110];
    11 
    12 void FWT(ll x[],int len,int mode)
    13 {
    14     for(int i=2;i<=len;i<<=1)
    15     {
    16         int step=i>>1;
    17         for(int j=0;j<len;j+=i)
    18             for(int k=j;k<j+step;k++)
    19             {
    20                 ll a=x[k],b=x[k+step];
    21                 x[k]=(a+b)%MOD;
    22                 x[k+step]=(a-b+MOD)%MOD;
    23                 if(mode==-1) (x[k] *= inv_2)%=MOD,(x[k+step]*=inv_2)%=MOD; 
    24             }
    25     }
    26 }
    27 
    28 int get(int x)
    29 {
    30     int res = 0;
    31     for (int i = 19; i >= 0; i -= 2)
    32     {
    33         int a = (x >> i) & 1, b = (x >> (i - 1)) & 1;
    34         if (a == 1 && b == 0) res += 4;
    35         else if (a == 1 && b == 1) res += 1;
    36         else res += (a << 1) + b;    
    37     }
    38     return res;
    39 }
    40 
    41 int main()
    42 {
    43     while (scanf("%d", &n) != EOF)
    44     {
    45         memset(c, 0, sizeof c);
    46         memset(a, 0, sizeof a); 
    47         for (int i = 1, x; i <= n; ++i)
    48         {
    49             int tmp = 0; 
    50             for (int j = 1; j <= 10; ++j) 
    51             {
    52                 scanf("%d", &x);
    53                 if (x == 0) tmp <<= 2;
    54                 else if (x == 1) tmp <<= 2, tmp += 1;
    55                 else if (x == 2) tmp <<= 1, tmp += 1, tmp <<= 1;  
    56             }
    57             ++c[tmp];
    58         }
    59         FWT(c, 1 << 20, 1);
    60         for (int i = 0; i <= 1 << 20; ++i) c[i] = (c[i] * c[i]) % MOD; 
    61         FWT(c, 1 << 20, -1);     
    62         for (int i = 0; i <= 1 << 20; ++i)
    63             a[get(i)] += c[i];  
    64         ll res = 0;
    65         for (int i = 0; i <= 40; ++i) res = (res + a[i] * a[i] % MOD) % MOD; 
    66         printf("%lld
    ", res);
    67     }
    68     return 0;
    69 }
    View Code
  • 相关阅读:
    linux搭建svn服务器
    Cmder添加到右键菜单
    linux系统配置本地软件仓库
    pom文件parent标签的使用,parent版本号报红线(很明显引用的是本地自己的包)
    Redis学习记录-001
    (概念总结)快速了解JVM结构和工作原理
    Java 设计模式(七)《抽象工厂模式》
    多线程间通信wait(),notify(),notifyAll()
    快速了解数据结构
    JDK1.8 Consumer & Supplier 什么意思
  • 原文地址:https://www.cnblogs.com/Dup4/p/10327868.html
Copyright © 2011-2022 走看看