首页 > 其他分享 >1.7 CW 模拟赛 赛时记录

1.7 CW 模拟赛 赛时记录

时间:2025-01-07 14:34:28浏览次数:1  
标签:mathbb 1.7 赛时 int MAXN mathcal rm 考虑 CW

前言

这次没复习直接上, 无敌了

还是策略 + 时间分配, 好好考

看题

大样例发的有点神经的

\(\rm{T1}\)

什么数数题, 红温了, 不太看得出来的样子

\(\rm{T2}\)

有点神秘

\(\rm{T3}\)

又是数数, 无语了

\(\rm{T4}\)

神秘


首先应该是普通难度, 打不了的题先跳过, 先拿暴力分, 不要死磕

\(\rm{T1}\)

思路

作为一个刚学了一堆数数 \(\rm{trick}\) 的人, 看看能不能冲一下正解

转化题意

对于一个 \(n\) 行 \(m\) 列的 \(01\) 矩阵, 求有多少种行数的集合, 使得翻转这些行以后每一列至多有一个 \(1\)

\(60 \%\) 给状压, 好像还不是很稳

通过简单转化我们可以知道, 对于 \(m\) 列, 有哪些集合及集合的反转会使这一位有 \(1\), 记为 \(\mathbb{U}\)
考虑正难则反算至少有一列至少有两个 \(1\) 的情况, 也就是说, 我们随意挑选至少一列的 \(\mathbb{U}\) 中的两个集合 (不能是一个集合和其反转不能同时选择) , 就可以产生一种非法情况

考虑非法情况的计数


好吧时间不够了, 先考虑暴力, 最后有时间再想正解

对于 \(20 \%\) , 先处理选择的行的集合, 然后 \(\mathcal{O} (nm)\) \(\rm{check}\) 即可, 总时间复杂度 \(\mathcal{O} (2^n nm)\)

对于 \(40 \%\) , 我们考虑状压 \(\rm{dp}\)
令 \(f_{i, \mathbb{S}}\) 表示考虑了前 \(i\) 行, 当前的放 \(1\) 情况为 \(\mathbb{S}\) 时的方案数
考虑转移, 记 \(s_i\) 表示第 \(i\) 行不反转时 \(1\) 的位置集合, \(s^{\prime}_i\) 表示第 \(i\) 行反转时 \(1\) 的位置集合

\[\begin{align*} \forall \mathbb{S} \cap s_i = \varnothing , f_{i - 1, \mathbb{S}} \to f_{i, \mathbb{S} \cup s_i} \\ \forall \mathbb{S} \cap s^\prime_i = \varnothing , f_{i - 1, \mathbb{S}} \to f_{i, \mathbb{S} \cup s^\prime_i} \end{align*} \]

总时间复杂度 \(\mathcal{O} (n 2^m)\)

实现

框架

实现两个部分

  • \(n\) 较小时
    暴力模拟即可
  • \(m\) 较小时
    如上状压 \(\rm{dp}\) 即可

代码

/*对于 n 较小时的做法*/
class subtask1
{
private:
    bool chose[MAXN];
    bool check(int S) {
        int cnt = 0;
        for (int i = 1; i <= n; i++) chose[i] = (S >> (i - 1)) & 1;
        for (int i = 1; i <= m; i++) {
            int res = 0;
            for (int j = 1; j <= n; j++) {
                if (chose[j]) res += (mat[j][m - i + 1] == '1');
                else res += (mat[j][i] == '1');
            }
            if (res > 1) return false;
        }
        return true;
    }

public:
    void solve() {
        int ans = 0;
        for (int S = 0; S < (1 << n); S++) // 外层枚举选行的状态
            if (check(S)) ans++;
        printf("%lld\n", ans);
    }
} sub1;

/*对于 m 较小时的做法*/
class subtask2
{
private:
    int f[2][MAXVAL];

    int s1[MAXN], s2[MAXN];
    /*预处理 s_i, s'_i*/
    void init() {
        for (int i = 1; i <= n; i++) {
            s1[i] = s2[i] = 0;
            for (int j = 1; j <= m; j++) {
                if (mat[i][j] == '1') s1[i] += (1 << (j - 1));
                if (mat[i][m - j + 1] == '1') s2[i] += (1 << (j - 1));
            }
        }
    }

public:
    void solve() {
        init();
        int now = 0, nxt = 1;
        memset(f, 0, sizeof(f)); f[now][0] = 1;
        for (int i = 0; i < n; i++) {
            memset(f[nxt], 0, sizeof(f[nxt]));
            for (int S = 0; S < (1 << m); S++) {
                if (!(S & s1[i + 1])) f[nxt][S | s1[i + 1]] += f[now][S];
                if (!(S & s2[i + 1])) f[nxt][S | s2[i + 1]] += f[now][S];
            }
            std::swap(now, nxt);
        }
        int ans = 0;
        for (int S = 0; S < (1 << m); S++) ans += f[now][S];
        printf("%lld\n", ans);
    }
} sub2;

\(\rm{T2}\)

目前得分: \(60 \ \rm{pts}\)

思路

不是数数, 加油冲冲冲

看到这个形式就想转差分, 不管怎么样先用这个思路转化题意

给定一个序列 \(a\) , 每次操作你可以任取 \(i \in [1, n]\) , 将 \(a_i + 1, a_{i + 1} - 1\) 或者将 \(a_i - 1, a_{i + 1} + 1\) , 求至多 \(k\) 此操作后, 最长的连续 \(1\) 有多长 ( \(a_1, a_{n + 1}\) 不计入统计)

你发现 \(k\) 很大, 也属于一种提醒, 不能一次一次模拟

\(666\) , 根本不会做

实现

考虑 \(10 \%\)

#include <bits/stdc++.h>
const int MAXN = 1e5 + 20;
int T;
int n, k, a[MAXN], dif[MAXN];

int main()
{
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &k);
        for (int i = 1; i <= n; i++) scanf("%d", &a[i]), dif[i] = a[i] - a[i - 1];

        int ans = 0;
        int res = 0;
        for (int i = 2; i <= n; i++) {
            if (dif[i] == 1) { res++; ans = std::max(res, ans); }
            else res = 0;
        }
        printf("%d\n", ans + 1);
    }

    return 0;
}

\(\rm{T4}\)

目前得分: \(70 \ \rm{pts}\)

思路

这题能骗多少骗多少

\(30 \%\) 给了暴力模拟, 维护每个串串当前的首位, 然后暴力计算即可
考虑 \(n = 2\) , 暴力枚举会 \(\rm{TLE}\) , 怎么做
考虑 \(l_i \leq 2\) , 暴力枚举会 \(\rm{TLE}\) , 怎么做

急急急, 把 \(30 \%\) 打完去冲 \(\rm{T3}\) 的 \(\mathcal{O} (nk)\)

实现

框架

模拟模拟

代码

#include <bits/stdc++.h>
const int MAXN = 6;
const int MAXL = 6;
#define lcm(a, b) a / std::__gcd(a, b) * b

int T;
int n, m;
int a[MAXN][MAXL];
int l[MAXN];

int main()
{
    scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &m);
        int times = 1;
        for (int i = 1; i <= n; i++) {
            scanf("%d", &l[i]); times = lcm(times, l[i]);
            for (int j = 1; j <= l[i]; j++) scanf("%d", &a[i][j]);
        }
        for (int i = 1; i <= m; i++) {
            int ans = 0;
            int head[MAXN];
            memset(head, 0, sizeof(head));
            for (int j = 1; j <= times; j++) {
                for (int k = 1; k <= n; k++) head[k] = ((head[k] + 1) > l[k] ? 1 : head[k] + 1);
                int res = 0;
                for (int k = 1; k <= n; k++) {
                    if (a[k][head[k]] == i) { res++; ans = std::max(ans, res); }
                    else res = 0;
                }
            }
            printf("%d ", ans);
        }
        printf("\n");
    }

    return 0;
}

\(\rm{T3}\)

目前得分: \(100 \ \rm{pts}\)

思路

现在优势一点都不在我, 主要是 \(\rm{T2}\) 基本上啥都不会, 寄!

又是数数, 看看这题够不够典

转化题意

给定一棵 \(n\) 节点的树, 求删边边集的数量, 使得剩余部分的连通块大小均为 \(k\) 或者 \(k + 1\)

怎么又是和 \(\rm{T1}\) 很像的形式, 不是哥们
不过这个题像树形 \(\rm{dp}\)


好吧也是再次没想出来

考虑 \(10 \%\) 直接状态压缩之后 \(\mathcal{O} (n)\) \(\rm{check}\)

还有个链的 \(10 \%\) 考虑动态规划
具体的, 令 \(f_{u, s}\) 表示对于 \(u\) 这个点, 其带了一个大小为 \(s\) 的连续块过来的方案数
初始化 \(f_{leave, 1} = 1\)
考虑转移 (假设 \(u\) 的下一个点为 \(v\) )

\[\begin{align*} & f_{u, 1} \gets f_{v, k} + f_{v, k + 1} \\ & f_{u, s} \gets f_{v, s - 1} \end{align*} \]

然后发现数组开不下? 直接打完 \(10 \%\) 跑路, 不过这个好像可以拓展成 \(60 \%\)

不过问题是 \(\rm{T4}\) 部分分很足, 先开 \(\rm{T4}\) , 这 \(10 \%\) 留到后面, 还有时间就把 \(60 \%\) 打了


好好好, 剩余的时间全部冲这题的 \(\mathcal{O} (nk)\) , 先手模一遍确定正确性
我样例呢?!

好好好, 正确性没问题, 但转移方式还要细想

考虑对于 \(u\) 子树及其儿子 \(son(u)\) , 怎么转移
容易发现的是我们可以一颗子树一颗子树的加入, 不影响答案
考虑对于 \(f_{u, i}\) , 会从哪些 \(v\) 的地方产生贡献
怎么怎么搞都是 \(\mathcal{O} (n k^2)\) 的, 红温了
考虑类似树上背包的形式, 还是只能到 \(\mathcal{O} (n k^2)\)

实现

只能打个暴力了

#include <bits/stdc++.h>
const int MAXN = 21;
const int MOD = 998244353;

int n, k;
struct node {
    int to, next;
} edge[MAXN << 1];
int cnt = 0, head[MAXN];
void init() {
    cnt = 0;
    for (int i = 1; i <= n; i++) head[i] = -1;
}

void addedge(int u, int v) {
    edge[++cnt].to = v, edge[cnt].next = head[u];
    head[u] = cnt;
}

int sz;
bool canuse[MAXN << 1];
bool vis[MAXN];
void dfs(int now) {
    sz++;
    vis[now] = true;
    for (int i = head[now]; ~i; i = edge[i].next) {
        int nowto = edge[i].to;
        if (vis[nowto] || !canuse[i]) continue;
        dfs(nowto);
    }
}

bool check(int s) {
    memset(canuse, false, sizeof(canuse)); memset(vis, false, sizeof(vis));
    int ret = 0;
    while (s) {
        ret++;
        if (s & 1) {
            canuse[ret] = canuse[ret + 1] = true;
        } else {
            canuse[ret] = canuse[ret + 1] = false;
        }
        ret++;
        s >>= 1;
    }

    for (int i = 1; i <= n; i++) {
        sz = 0;
        if (!vis[i]) dfs(i);
        if (sz != k + 1 && sz != k && sz) return false;
    }
    return true;
}

int main()
{
    int T; scanf("%d", &T);
    while (T--) {
        scanf("%d %d", &n, &k);
        init();
        for (int i = 1; i < n; i++) {
            int u, v;
            scanf("%d %d", &u, &v);
            addedge(u, v), addedge(v, u);
        }

        int ans = 0;
        for (int i = 0; i < (1 << (n - 1)); i++) {
            if (check(i)) ans = (ans + 1) % MOD;
        }
        printf("%d\n", ans);
    }

    return 0;
}

后记

\(\rm{qtmd}\) , 破大防

标签:mathbb,1.7,赛时,int,MAXN,mathcal,rm,考虑,CW
From: https://www.cnblogs.com/YzaCsp/p/18657550

相关文章

  • 德普微一级代理 DP023N10TGN TOLL DPMOS N-MOSFET 100V 300A 1.75mΩ
    Features•UsesadvancedTrenchMOSFET-DPMOStechnology•Extremelylowon-resistanceRDS(on)•ExcellentQgxRDS(on)product(FOM)•QualifiedaccordingtoJEDECcriteriaProductSummaryPart#:DP023N10TGNVDS:100VRDS(on).typ:1.75m......
  • WebAudioContext.createPeriodicWave
    PeriodicWaveNodeWebAudioContext.createPeriodicWave(Float32Arrayreal,Float32Arrayimag,objectconstraints)小程序插件:不支持功能描述创建一个PeriodicWaveNode参数Float32Arrayreal一系列余弦术语(传统上的A项)Float32Arrayimag一系列正弦项(传统上的B项)o......
  • AcWing 799:最长连续不重复子序列 ← 双指针
    【题目来源】https://www.acwing.com/problem/content/801/【题目描述】给定一个长度为n的整数序列,请找出最长的不包含重复的数的连续区间,输出它的长度。【输入格式】第一行包含整数n。第二行包含n个整数(均在0∼10^5范围内),表示整数序列。【输出格式】共一行,包含一个......
  • 01.03 CW 模拟赛 T4. ring
    前言找原题未遂了()\(\rm{HD0X}\)大佬讲了没听懂啊思路无敌了,看起来似乎很困难,不知道补不补的掉首先发现不好处理成一种简单的问题,肯定是想有哪些方法可以处理这种问题\(\rm{TJ}\)的不太看得懂你可以树状数组维护区间和,每次对于一个环暴力修改\(\mathcal{O}(s......
  • 01.03 CW 模拟赛 T2. game
    思路先把赛时的思路搬一下你发现确定两个人的起始点,其实是可以确定\(\rm{Alice}\)的选点可能的,考虑写个代码验证一下具体的,就是分成两个弧,\(\rm{Alice}\)可以选择一个弧的优势(过半),然后其他的劣势感觉现在是猜结论,全靠感性,我也不知道怎么解释这个问题那么......
  • 01.03 CW 模拟赛 T1. math
    前言赛场上\(\rm{while}\)打成\(\rm{if}\)痛失\(40\rm{pts}\)不过下来看是贪心的话也没什么好做的了,一般都不会对了这是题目题目下载\(\rm{sol}\)方法\(1\):逐位计算思路显然的是你需要把数字从大到小填入,使得高位的数尽量大,这个显然由上面的结论可以知道......
  • 1.3 CW 模拟赛 赛时记录
    前言还是传统手法,冲冲冲看题\(\rm{T1}\)好吧,不会高精度,寄了\(\rm{T2}\)博弈\(\rm{T3}\)我不到啊\(\rm{T4}\)看不懂思密达首先这套题肯定不是能拿大分的题,所以今天尽量多分析,给每个题留足思考时间,然后多打暴力,最后拼高分/正解以后也尽量做到看题的时......
  • Apache Doris 软件部署(2.1.7版本)
    软件介绍:ApacheDoris介绍_rustapachedoris-CSDN博客一、软件依赖环境配置1、检查软硬件环境cat/proc/cpuinfo|grepavx2如果没有返回,则不支持avx2,后续下载包有影响2、设置系统最大打开文件句柄数vi/etc/security/limits.conf添加如下内容*softnofile100000......
  • AcWing 791:高精度加法 ← string+数组
    【题目来源】https://www.luogu.com.cn/problem/P1601https://www.acwing.com/problem/content/793/【题目描述】高精度加法,相当于a+bproblem,不用考虑负数。输入不含前导0。【输入格式】分两行输入。a,b≤10^500。【输出格式】输出只有一行,代表a+b的值。【输入样例】1......
  • 11.7 图像增强与动漫化一
    packageorg.example;importorg.json.JSONObject;importjava.io.BufferedReader;importjava.io.IOException;importjava.io.InputStreamReader;importjava.net.HttpURLConnection;importjava.net.URL;importjava.util.logging.Level;importjava.util.loggin......