首页 > 其他分享 >2024CCPC网络赛题解

2024CCPC网络赛题解

时间:2024-09-08 20:36:13浏览次数:11  
标签:const int 题解 网络 long sum2 2024CCPC sum1 define

前言

开局掉线30min比较搞心态,不过比赛延迟了1个小时,但是后面也一直没过题,如果时间再少点可能排名还更好看。最后是8题前面,这里简单讲一下我有写的题,队友写的题就放一下队友的赛时代码,大家自己看看吧。

B

队友写的,签到,但是数据范围 \(n\) 给 \(10^3\) 给队友整不自信了,因为答案的那个结论成立的话很显然可以 \(nlogn\) 做,可能是为了让大家能 \(n^2\) 求不整齐度吧。

代码

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
const int M = 998244353;

int frac(int n){
    int re=1;
    for(int i=1;i<=n;i++)re=re*i%M;
    return re;
}

signed main() {
   ios::sync_with_stdio(0);
   cin.tie(0), cout.tie(0);
    int n;
    cin>>n;
    set<int>s;
    map<int,int>mp;
    int a[n];
    for(int i=0;i<n;i++)cin>>a[i],mp[a[i]]++,s.insert(a[i]);
    sort(a,a+n);
    int ans=0;
    int cnt=1;
    for(auto [p,t]:mp)cnt=cnt*frac(t)%M;
    if(s.size()>1)cnt*=2;
    for(int i=0;i<n;i++)
     for(int j=i;j<n;j++){
        ans+=a[j]-a[i];
     }
    cout<<ans<<" "<<cnt%M;

  //  system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

D

队友写的,区间DP

代码

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int N = 109;
const int mod = 998244353;
int dp[N][N][N], n, m;
string S, T;
signed main() {
     ios::sync_with_stdio(0);
     cin.tie(0), cout.tie(0);
    cin >> S >> T;
    n = S.length();
    m = T.length();
    S = ' ' + S;
    T = ' ' + T;
    for(int i = 0; i <= n; i++)
        for(int j = 1; j <= m+1; j++)
            for(int t = 0; t < j; t++)
                dp[i][j][t] = 1;
    for(int i = 1; i <= n; i++){
        for(int l = 1; l <= m; l++)
            for(int r = l; r <= m; r++){
                for(int k = l-1; k <= r; k++)
                    dp[i][l][r] = (dp[i][l][r] + dp[i-1][l][k] * dp[i-1][k+1][r]) % mod;
                for(int k = l-1; k < r; k++)
                    if(S[i] == T[k+1])
                        dp[i][l][r] = (dp[i][l][r] + dp[i-1][l][k] * dp[i-1][k+2][r]) % mod;    
            }
    }
    cout << dp[n][1][m] << '\n';
    //system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

E

和队友一起推的式子,我写的代码,这里可以稍微讲讲。
对于trie树上的一个节点,表示的是一个前缀。那么这个节点存在,说明 \(n\) 个字符串里至少有一个串包括这个前缀即可,那么概率就是 \(1- P(这个前缀不出现)\),而这个前缀不出现,则所有 \(n\) 个串都不能有这个前缀。显然这 \(n\) 个串是独立的,所以只需要求出一个串不包含这个前缀的概率,拿去 \(n\) 次方即可。那么对于一个串,不包含这个前缀的概率,又等于 \(1 - P(包含这个前缀的概率)\),包含这个前缀(假设长度为 \(i\))的概率显然为 \((\frac{1}{26} ^ i)\)。又因为所有长度为 \(i\) 的前缀都是等价的,所以还要再最外面考虑乘一个 \(26^i\)表示所有长度为 \(i\) 的前缀的数量。综上,最后trie树的期望节点数就是

\[1 + \sum_{i = 1} ^ m (26^i \times (1 - (1 - (\frac{1}{26})^n))) \]

至于最多的节点数,则分层考虑,第一层最多有 26 个,第二层最多有 \(26^2\)个,以此类推,第 \(i\) 层最多有 \(26^i\) 个,而且因为每一层都至少对应这 \(n\) 个串中的1个,所以每一层最多的结点数还要跟 \(n\) 取个最小值,所以最后的答案就是:

\[1 + \sum{i = 1}{m}min(26^i, n) \]

代码

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int maxn = 1e5 + 1000;
const int mod = 998244353;
int mi26[maxn];
int ksm(int a, int b) {
    int res = 1;
    for (; b; b >>= 1, a = a * a % mod) {
        if (b & 1) res = res * a % mod;
    }
    return res;
}
signed main() {
    // ios::sync_with_stdio(0);
    // cin.tie(0), cout.tie(0);
    mi26[0] = 1;
    for (int i = 1; i < maxn; i++)
        mi26[i] = mi26[i - 1] * 26 % mod;
    int inv26 = ksm(26, mod - 2);
    int n, m; cin >> n >> m;
    int ans1 = 1;
    for (int i = 1; i <= m; i++) {
        ans1 += mi26[i] * ((1 - ksm((1 - ksm(inv26, i) + mod) % mod, n) + mod) % mod) % mod;
        ans1 %= mod;
    }
    int ans2 = 1, tem = 1;
    for (int i = 1; i <= m; i++) {
        tem *= 26;
        if (tem < n) ans2 += tem, ans2 %= mod;
        else {
            ans2 += (m - i + 1) * n % mod;
            ans2 %= mod;
            break;
        }
    }
    cout << ans2 << " " << ans1 << "\n";
    system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

G

队友写的,网络流
看到数据范围 \(10^3\) 就开始考虑可能是一些科技东西,就往网络流考虑了,然后发现那些限制刚好也很符合网络流,具体建图不太清楚,好像是先考虑一下打车钱,然后两个人一起付钱就可以建虚点啥的,最后看能不能跑满最大流,直接看代码吧。

代码

点击查看代码
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int N = 3e3+99;
const int mod = 998244353;
struct Edge{
    int v, nxt, w;
}e[N*10];
int head[N], cur[N], tot = 1, s, t, dist[N], gap[N], sz;
ll dfs(int u, ll rest) {
    if (u == t) return rest;
    ll sum = 0;
    for (int &i = cur[u]; i; i = e[i].nxt) {
        if (dist[u] == dist[e[i].v] + 1 && e[i].w) {
            ll ret = dfs(e[i].v, min(rest, e[i].w));
            rest -= ret;
            sum += ret;
            e[i].w -= ret;
            e[i ^ 1].w += ret;
            if (rest == 0) return sum;
        }
    }
    gap[dist[u]]--;
    if (gap[dist[u]] == 0) dist[s] = sz + 1;
    dist[u]++;
    gap[dist[u]]++;
    cur[u] = head[u];
    return sum;
}
ll isap() {
    gap[0] = sz;
    ll ans = 0;
    while (dist[s] < sz) ans += dfs(s, inf);
    return ans;
}
void add(int u, int v, int w, int t = 1){
    e[++tot] = (Edge){v, head[u], w};
    head[u] = tot;
    if(t) add(v, u, 0, 0);
}
int a[N], val[N];
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
        cin >> a[i] >> val[i];
    s = n + m + 1, t = s + 1;
    sz = t;
    int sum = 0, flow = 0;    
    for(int i = 1; i <= m; i++){
        int x, y, w;
        cin >> x >> y >> w;
        add(x, n + i, inf);
        add(y, n + i, inf);
        add(n + i, t, w);
        flow += w;
        if(x == 1 || y == 1) sum += w;
    }
    sum = min(a[1], sum + val[1]);
    bool flag = 1;
    add(s, 1, sum - val[1]);
    for(int i = 2; i <= n; i++){
        a[i] = min(a[i], sum-1);
        if(a[i] < val[i]){
            flag = 0;
            break;
        }
        add(s, i, a[i] - val[i]);
    }
    if(!flag || isap() < flow)
        cout << "NO\n"; 
    else
        cout << "YES\n";
    //system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

I

队友写的,是个三次方的dp,好像是预处理一个数组 \(ans[i]\) 表示拿到行李时间大等于 \(i\) 的方案数,这个数组是用三方的dp来求的,最后就可以差分得出每个时间的方案数,再求和啥的。

代码

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
const int M = 998244353;
signed main() {
    // ios::sync_with_stdio(0);
    // cin.tie(0), cout.tie(0);
    int n, m;
    cin >> n >> m;
    int a[n + 1]{};  // xingli
    int b[m + 1]{};  // ren
    int ans[606]{};
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    for (int i = 1; i <= m; i++)
        cin >> b[i];
    sort(a + 1, a + 1 + n);
    sort(b + 1, b + 1 + m);
    for (int k = 0; k <= 500; k++) {
        int dp[505][505]{};
        dp[0][0] = 1;
        int a1[n + 1]{};
        int pre[1050]{};
        for (int i = 1; i <= n; i++)
            a1[i] = a[i] + k, pre[a1[i]]++;
        for (int i = 1; i <= 500; i++)
            pre[i] += pre[i - 1];

        for (int j = 1; j <= m; j++)
            for (int i = 0; i <= 500; i++) {
                if (i - pre[b[j]] + pre[b[j - 1]] >= 0)
                    dp[i][j] += dp[i - pre[b[j]] + pre[b[j - 1]]][j - 1];
                if (i - pre[b[j]] + pre[b[j - 1]] + 1 >= 0)
                    dp[i][j] += dp[i - pre[b[j]] + pre[b[j - 1]] + 1][j - 1] *
                                (i + 1) % M;
                dp[i][j] %= M;
            }
        for (int i = 0; i <= n; i++)
            ans[k] += dp[i][m], ans[k] %= M;
    }
    int res = 0;

    for (int i = 1; i <= 500; i++) {
        res += (ans[i - 1] - ans[i] + M) % M * (i - 1) % M;
        res %= M;
    }
    cout << res;
    // system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

J

和队友一起讨论出来,最后我写的,首先转化题意
两个数组分别异或,得到 sum1 和 sum2,容易发现如果交换 \(a_i\) 和 \(b_i\) 则 \(sum1 - sum1 ^ a[i] ^ b[i]\),sum2同理,所以题意转化为,有两个数sum1 和 sum2,还有 \(n\)个数 \(a_i \oplus b_i\) 你可以任意选择这 \(n\) 个数的若干个数,让 sum1 和 sum2同时异或上它们,问 \(max(sum1, sum2)\) 的最小值是多少。
由于是任意选择若干个数异或,显然可以考虑线性基,然后从高到低按位贪心考虑。如果sum1 和sum2这一位都是0,则不操作,若这一位都是1,则去异或线性基的这一位。难点在于一个1一个0的情况,这时候选不选择去异或,都不影响答案的这一位,但是选择异或,可能会对后面的位产生影响。
这时候一开始我有个错误的思路,碰到这样的数,我就不去异或,而是把线性基里的对应数去掉当前位,重新插入线性基。然而wa了之后队友发现这样假了,随便比如111和000,假如线性基里都有数,那么我就都不操作了,而明显可以通过交换这两个数的这一位可以使较大的数减小一些。
所以思路就有了,遇到一个0一个1的情况,可以通过异或线性基的这一位,交换这两个数的这一位。那么该怎么交换合理,又要考虑前面的位,如果已经有不一样的,那么大的数肯定一直都大(因为二进制下,从高到低第一个不同的位决定了数的大小),所以后面可以选择交换0、1的地方,就把1都分配给较小的数,所以后面这样的决策都是确定的。如果前面的位都一样呢?这里我是直接比较暴力的,把异或和不异或两种情况都跑一次,取个最小值,因为这一位开始,后面的决策也都确定,所以跑2次复杂度也是正确的。

代码

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int maxn = 1e6 + 10;
const int mod = 998244353;
int p[33];
int a[maxn], b[maxn];
void insert(int x) {
    for (int i = 31; i >= 0; i--) {
        if ((x >> i) == 0) continue;
        if (!p[i]) {
            p[i] = x;
            break;
        } else x = x ^ p[i];
    }
}
int dfs(int pos, int sum1, int sum2) {
    if (pos == -1) return max(sum1, sum2);
    int x1 = ((sum1 >> pos) & 1);
    int x2 = ((sum2 >> pos) & 1);
    if (x1 == 0 && x2 == 0) return dfs(pos - 1, sum1, sum2);
    if (x1 == 1 && x2 == 1) return dfs(pos - 1, sum1 ^ p[pos], sum2 ^ p[pos]);
    if ((x1 == 1 && sum1 > sum2) || (x2 == 1 && sum2 > sum1)) {
        return dfs(pos - 1, sum1 ^ p[pos], sum2 ^ p[pos]);
    } else {
        return dfs(pos - 1, sum1, sum2);
    }
}
void solve() {
    memset(p, 0, sizeof p);
    int n; cin >> n;
    int sum1 = 0, sum2 = 0;
    for (int i = 1; i <= n; i++) cin >> a[i], sum1 ^= a[i];
    for (int i = 1; i <= n; i++) cin >> b[i], sum2 ^= b[i];
    for (int i = 1; i <= n; i++) {
        insert(a[i] ^ b[i]);
    }
    for (int i = 31; i >= 0; i--) {
        int x1 = ((sum1 >> i) & 1);
        int x2 = ((sum2 >> i) & 1);
        if (x1 == 0 && x2 == 0) continue;
        if (x1 == 1 && x2 == 1) sum1 ^= p[i], sum2 ^= p[i];
        else {
            if ((sum1 >> (i + 1)) != (sum2 >> (i + 1))) {
                if ((x1 == 1 && sum1 > sum2) || (x2 == 1 && sum2 > sum1)) {
                    cout << dfs(i - 1, sum1 ^ p[i], sum2 ^ p[i]) << "\n";
                } else {
                    cout << dfs(i - 1, sum1, sum2) << "\n";
                }
                return;
            }
            else {
                int ans = min(dfs(i - 1, sum1, sum2), dfs(i - 1, sum1 ^ p[i], sum2 ^ p[i]));
                cout << ans << "\n";
                return;
            }
        }
    }
    cout << max(sum1, sum2) << "\n";
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while (t--)
        solve();
    // system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

K

签到,首先容易发现,奇数,先手肯定取1,之后就都只能拿1,先手胜。拓展一下就可以考虑所有 \(n\) 的因数,如果有奇数个它,那么先手就取这个数,后手无论怎么选,先手都可以取一样的数模仿。然后考虑哪个因数使得 \(n\) / 它是奇数,发现似乎是2的若干次幂,进而发现是 \(lowbit(n)\),所以最后只要判断一下 \(lowbit(n)\) 和 \(k\) 的大小,就可以直接输出了。

代码

点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
const int mod = 998244353;
void solve() {
    int n, k; cin >> n >> k;
    if ((n & (-n)) <= k)
        cout << "Alice\n";
    else
        cout << "Bob\n";
}
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t; cin >> t;
    while (t--)
        solve();
    // system("pause");  // 交之前记得注释一下,关流的时候不会显示输出
    return 0;
}

L

纯模拟,暴力找,没什么好说的

代码

点击查看代码
#include <bits/stdc++.h>
// #define int long long
#define pii pair<int, int>
#define ll long long
using namespace std;
const int maxn = 5e2 + 10;
const int mod = 998244353;
char ch[maxn][maxn];
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int n, m; cin >> n >> m;
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            cin >> ch[i][j];
        }
    int ans = 0;
    for (int i = 1; i < n; i++)
        for (int j = 1; j < m; j++) {
            if (ch[i][j] == 'c' && ch[i][j + 1] == 'c' && ch[i + 1][j] == 'p' && ch[i + 1][j + 1] == 'c')
                ans++;
        }
    cout << ans << endl;
    // system("pause");
    return 0;
}

标签:const,int,题解,网络,long,sum2,2024CCPC,sum1,define
From: https://www.cnblogs.com/TJUHuangTao/p/18403408

相关文章

  • 网络设备开局配置生成器(第三次更新) QQ交流群:(4817315)
     网络设备开局配置生成器(SecureCRTvbs脚本)QQ交流群:(4817315)一、工具介绍本工具主要是针对简化网络工程师重复繁琐的工作而开发。工具只是将重复工作通过自己配置生成脚本代码来执行,工具的大致功能可以概括为以下几点:1.可以1分钟生成华为、华三、锐捷等交换机的开......
  • 汽车网络安全的未来:将车辆视为端点
    汽车行业面临着许多与其他行业的成功企业相同的网络安全风险和威胁,但它也在应对一些独特的风险和威胁。Nuspire的首席威胁分析师JoshSmith(一家在汽车领域有着深厚根基并保护通用汽车和斯巴鲁等客户的托管安全服务提供商)谈到了当前的风险和威胁,并对汽车网络安全的未来发表......
  • 虚拟机网络配置大纲
    目录一、ping测试主机之间网络连通性二、修改虚拟网卡ip三、修改IP配置文件四、ifconfig配置网络接口五、修改主机名称和hosts映射文件一、ping测试主机之间网络连通性ping测试主机之间网络连通性pingwww.baidu.comwww.jd.com…二、修改虚拟网卡ip修改虚拟......
  • AT_dwacon6th_prelims_c Cookie Distribution 题解
    组合意义保平安。思路发现\(\prod\)的贡献不好统计。我们可以考虑\(\prod\)的组合意义。容易发现:\[\prodc_i=\prod\sum_{j=1}^{c_i}1\]那么依照分配律,我们发现这个东西的组合意义是每个人从获得的饼干中选一个出来的方案。这样就会变好统计很多。设\(dp_{i,j}\)为......
  • 深度学习|激活函数:网络表达增强
    文章目录引言常见的激活函数阶跃函数**Sigmoid****ReLU****LeakyReLU****Softmax****Tanh**恒等函数对比分析梯度问题可训练性结语引言在前文对M-P神经元结构的介绍以及「深度学习|模型推理:端到端任务处理」的推理过程演示中,我们反复提到了激活函数......
  • 计算机网络(第8版)第三章 数据链路层(3.5)
    3.5高速以太网3.5.1 100BASE-T以太网又称为快速以太网(FastEthernet)。在双绞线上传送100Mbit/s基带信号的星形拓扑以太网。仍使用IEEE802.3的CSMA/CD协议。1995定为正式标准:IEEE802.3u。1、100BASE-T以太网的特点可在全双工方式下工作而无冲突发生。......
  • 网络协议详解
    目录1.认识网络协议2网络协议的设计2.1网络通信的问题2.2网络协议的分层设计软件分层与网络分层3.OSI七层网络模型各层次的介绍如下4.TCP/IP五层协议各层次说明各层次所解决的问题5.网络和操作系统之间的关系单主机下多主机下6.重新理解网络协议1.认识网络协......
  • CF1534F2 Falling Sand (Hard Version) 题解
    题目链接点击打开链接题目解法做法1一个沙子消失,会带走所有它所在列下面的沙子我们记每列从下往上第\(a_i\)个沙子为关键点,第\(i\)列至少消失\(a_i\)个沙子等价于所有关键点都消失一个显然的事情是:记一列最上面的沙子为起始点,则我们只会干扰起始点第一感觉是找到一......
  • Prometheus(普罗米修斯)监控系统 - 2、网络等硬件设备监控(SNMP)
    文章目录前言一、群晖NAS1、开启SNMP服务2、测试3、MIB文档4、编写snmp.yml5、运行snmp-exporter6、加入Prometheus监控二、QNAPNAS1、开启SNMP服务2、SNMPMIB文件下载3、generate的使用4、运行snmp-exporter5、加入Prometheus监控三、华为防火墙1、开启SNM......
  • LOJ4218 「IOI2024」尼罗河船运 题解
    题目描述有\(n\)件手工艺品,第\(i\)件重量为\(w_i\),有参数\(a_i\)和\(b_i\)。每艘船最多可以运输两件手工艺品:如果只运输第\(i\)件,重量没有要求,代价为\(a_i\)。如果同时运输第\(i\)和第\(j\)件,要求\(|w_i-w_j|\leD\),代价\(b_i+b_j\)。\(q\)次询问,给......