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

12.28 CW 模拟赛 赛时记录

时间:2024-12-28 16:09:19浏览次数:1  
标签:12.28 赛时 int 连通 mathcal rm CW dp lld

前言

还是只管考试的策略, 别想其他的

每个题控制用时, 根据时间选择策略, 冷静

看题

完蛋了是 \(\rm{NOIP}\) , 我们没救了

\(\rm{T1}\)

怎么办, 像是很典的题但是我多半做不出来
别人做过容斥的肯定会, 但是我就不一样了

\(\rm{T2}\)

好像也不会做

\(\rm{T3}\)

基环树上的 \(\rm{dp}\) ?

\(\rm{T4}\)

有点像一位故人出的题

\(\rm{T1}\)

思路

题意非常清楚, 就是用 \(S\) 中的数字在 \([A, B]\) 区间中拼出 \(X\) 的倍数

你发现 \(A, B, X\) 是 \(10^{11}\) 数量级的, 很不好做

有倍数条件的同时还有数字的约束, 不太好做

你发现如果 \(S\) 是满的, 那么相当于问在 \([A, B]\) 区间中有多少个 \(X\) 的倍数, 这个是好求的

考虑引入 \(S\) 的限制, 朴素的想法是枚举倍数判断是否拥有其他数字, 这个显然不够优秀, 考虑有没有优化的方法

好吧我不会了, 打个暴力看下给了多少

代码

#include <bits/stdc++.h>
#define int long long

int X, A, B;
bool S[10];
int st; // 开始枚举的位置
int ans = 0;

bool check(int x) {
    while (x) {
        if (!S[x % 10]) return false; x /= 10; }
    return true;
}

signed main()
{
    scanf("%lld %lld %lld", &X, &A, &B);
    std::string a; std::cin >> a; for (int i = 0; i < a.length(); i++) S[a[i] - '0'] = true;
    st = (A % X) ? A / X + 1 : A / X; st *= X;

    for (int i = st; i <= B; i += X) {
        if (check(i)) ans++;
        if (clock() > 990) {
            printf("%lld", ans); return 0; }
    }
    printf("%lld", ans);

    return 0;
}

\(\rm{T2}\)

思路

这个题说不定比 \(\rm{T1}\) 可做?
好像明显有点畏难, 但是他一点提示没有不敢做

首先因为忘了欧氏距离是什么, 先玩一下样例

好的欧氏距离是, 对于两个点 \((x_1, y_1), (x_2, y_2)\) , 其欧氏距离 \(d = \sqrt{(x_1 - x_2)^2 + (y_1 - y_2)^2}\)

转化题意, 对于 \(n\) 个带权 \(k\) 的点, 任意两点 \(i, j\) 之间有双向连边, 其边权为 \(w_{i, j} = d_{i, j}\) , 求一最小阈值 \(C\) , 满足对于所有 \(w \leq C\) 的边连接后, 存在一个连通块 \(G\), 使得

\[\sum_{i = 1}^{\lvert G \rvert} (a_i \cdot k_i) \equiv 0 {\pmod K} , a_i \in \{0, 1\} \]

容易发现的是, 如果你要选择一些确定的点, 使其在同一连通块下, 那么你是可以求出最小阈值 \(C\) 的, 具体的, 我们可以二分之后 \(\rm{check}\) , 这个是 \(\mathcal{O} (n \log V)\) 的, 其中 \(V\) 是值域, 当然你也可以在确定 \(C\) 的情况下检查是否让老板开心

现在问题转化成了, 如何在一个图的连通块中, 判断是否可能有一些点的点权之和为 \(K\) 的倍数, 这个用可行性 \(\rm{dp}\) 可以解决

所以我们初步可以有一个暴力, 首先实数二分 \(V\) , 在这个基础上你把图的连通块跑出来 \(\mathcal{O} (n)\), 然后对于每个连通块进行可行性 \(\rm{dp}\)

好像还没说可行性 \(\rm{dp}\) 该怎么做

令 \(dp_{i, j}\) 表示考虑到第 \(i\) 个点权, 模 \(K\) 的结果是否能达到 \(j\) , 其中 \(dp_{i, j} \in \{0, 1\}\)

显然有转移

\[\begin{align*} dp_{i, j} \gets dp_{i - 1, j} \\ dp_{i, (j + k_i)} \gets dp_{i - 1, j} \end{align*} \]

其中 \(j\) 随时取模, 甚至可以滚掉 \(i\)


总结一下, 首先实数二分当前阈值 \(\mathcal{O} (\log V)\) , 然后跑当前图的情况和可行性 \(\rm{dp}\) \(\mathcal{O} (n\omega)\) , 其中 \(\omega = 30\) , 然后直接判断

总复杂度 \(\mathcal{O} (n \log V)\) , 可以通过本题

写的时候遇到了问题, 不能用 \(\mathcal{O} (n^2)\) 的方式建图, 我们需要在不计算原图的情况下找到连通块, 好像也不影响实现

实现

框架

实数二分, \(\rm{check}\) 比较复杂

代码

/*相信 O2 优化*/
#include <bits/stdc++.h>
// #define FILE_IO
#define int long long
const int MAXN = 5e4 + 20;
const double eps = 1e-4;
const int MAXVAL = 40;

#define dist(a, b) sqrt((double)(p[a].x - p[b].x) * (p[a].x - p[b].x) + (p[a].y - p[b].y) * (p[a].y - p[b].y))

int n, K;
struct node {
    int x, y, k;
} p[MAXN];

int be[MAXN], cnt;
/*辅助处理连通块的 bfs*/
void bfs(int now, int divnum, double C) {
    be[now] = divnum;
    for (int i = 1; i <= n; i++) {
        if (be[i] || dist(now, i) - C > eps) continue;
        bfs(i, divnum, C);
    }
}

std::vector<int> Div[MAXN];
/*在当前阈值情况下处理连通块*/
void divide(double C) {
    memset(Div, 0, sizeof(Div));
    for (int i = 1; i <= n; i++) be[i] = 0; cnt = 0;
    for (int i = 1; i <= n; i++) if (!be[i]) bfs(i, ++cnt, C);
    for (int i = 1; i <= n; i++) Div[be[i]].push_back(i);
}

/*检查阈值是否合法*/
bool check(double C) {
    divide(C);

    /*在当前连通块中处理可行性 dp*/
    for (int k = 1; k <= cnt; k++) {
        bool flag = false; // 是否可以整除
        int now = 0, nxt = 1;
        int dp[2][MAXVAL][2]; memset(dp, false, sizeof(dp)); dp[now][0][0] = true;
        for (int i = 0; i < Div[k].size(); i++) {
            std::swap(now, nxt); memset(dp[now], false, sizeof(dp[now]));
            int nowk = p[Div[k][i]].k;
            for (int j = 0; j < 40; j++) {
                dp[now][j][0] |= dp[nxt][j][0];
                dp[now][j][1] |= dp[nxt][j][1];
                dp[now][(j + nowk) % K][1] |= dp[nxt][j][0];
                dp[now][(j + nowk) % K][1] |= dp[nxt][j][1];
            }
            if (dp[now][0][1]) flag = true;
        }

        if (flag) return true;
    }
    return false;
}

/*二分答案*/
double binsearch() {
    double left = 0.0, right = 100000000.0;
    while (right - left > eps) {
        double mid = left + (right - left) / 2.0;
        if (check(mid)) right = mid;
        else left = mid;
    }
    return left;
}

signed main()
{
#ifdef FILE_IO
    freopen("connect_ex1.in", "r", stdin);
    freopen("connect_ex1.out", "w", stdout);
#endif

    scanf("%lld %lld", &n, &K);
    for (int i = 1; i <= n; i++) scanf("%lld %lld %lld", &p[i].x, &p[i].y, &p[i].k);
    // std::cout << check(1.3);

    double ans = binsearch();
    printf("%.3f", ans);

    return 0;
}

\(\rm{T3}\)

看起来很板的基环树上 \(\rm{dp}\) , 没时间做了

看起来也不能再写点什么了, 那就推推这个

套路的, 先考虑单棵树上怎么操作
令 \(f_{i, 0/1}\) 表示对于 \(i\) 的子树, 其中选不选当前点为关键点, 至少需要指定几个关键点才能符合要求

对于叶子节点的初始化是显然的, 考虑树形 \(\rm{dp}\) 的转移, 有

\[\begin{align*} f_{i, 0} \stackrel{k}{\longleftarrow} \left(\sum_{j = 1}^{\lvert son \rvert} f_{j, 0}\right) - f_{k, 0} + f_{k, 1} \\ f_{i, 1} \stackrel{k}{\longleftarrow} \left(\sum_{j = 1}^{\lvert son \rvert} f_{j, 0}\right) - f_{k, 0} + f_{k, 1} \end{align*} \]

显然的, 这样子会漏统计一种情况 : 子树的根节点本来是没有关键点与之相连的, 但是在 \(i\) 为关键点的时候子树成立

这个时候我们朴素的考虑往上加一维表示这个子树是否有关键点与之相连, 反正如果隔了一层一定不成立, 所以这样做是有正确性的

考虑令 \(f_{i, 0/1, 0/1}\) 表示对于 \(i\) 的子树, 其中选不选当前点为关键点, 当前子树的直接儿子中有没有关键点

\[\begin{align*} \end{align*} \]

标签:12.28,赛时,int,连通,mathcal,rm,CW,dp,lld
From: https://www.cnblogs.com/YzaCsp/p/18637574

相关文章

  • 2024.12.28模拟赛
    耳机没电了14:46耳机彻底没电了,可是我明明记得早上充了电的这应该是今年最后一次模拟赛了打了T1正解、T225分暴力与T410分暴力,实际T2挂了15分,总分115,排名第六现在也不知道暴力是怎么WA掉的今日作业T1【签到题】题目大意:给出一个长度为\(n\)的序列\(a_{i}\),要求......
  • 模拟赛 12.28 总结
    A.回文考虑一个串满足要求会是怎样的,他通过左-shift可以变成一个回文串,等价于一个回文串通过右-shift可以变成这个串,那么我们手玩可以发现要么这个串本身就是回文串,要么就是两个回文串且其中有一个长度是偶数拼起来的。首先第一个就不用说了显然满足,第二个的话可以这样想:假设......
  • 12.26 CW 模拟赛 T1. 平均
    思路首先你发现假设当前的平均数是\(a\),其中\(\lceila\rceil=k\),那么你势必要选上所有\(<k\)的数来拉低平均数,然后贪心的从小到大选\(\geqk\)的数来提高贡献如果想不到也可以这样想,对于一个确定的平均数,一定要尽可能的让比平均数小的数更多,才能更多的......
  • CW 12.26 模拟赛 赛时记录
    前言虽然说有点难受,但是还是好好考考试只需要管考试相关的即可,别想太多冷静,就这样看题先过一遍吧,看看感觉怎么样,今天时间要短一点,不开心\(\rm{T1}\)至少题意清楚,不管了\(\rm{T2}\)这么有实力,很像\(\rm{Indec\Sequence}\)\(\rm{T3}\)多半要观察性质......
  • 如何使用WGAN-GP生成一维滚动轴承振动数据样本。以西储大学(CWRU)数据集为例,提供一个基
    使用WGAN-GP生成一维滚动轴承振动数据样本。以西储大学(CWRU)数据集为例,提供一个基于训练好的权重参数文件进行测试的代码。WGAN-GP-1D轴承振动数据样本生成方法,西储大学数据集为例,可替换自己的数据。代码注释清楚,包含训练过程的代码train_gan和基于训练好的权重参数文件......
  • 12.24 CW 模拟赛 赛时记录
    前言考试期间,只需要考虑考试策略即可,别的都别管了先打暴力,想正解不超过\(40\\rm{min}\),最后拼高档/正解,冷静,认真分析看题现在看到不按难度排序已经免疫了,感觉是防锅专用语?\(\rm{T1}\)题意非常清楚,可能挖下性质还是可以做的\(\rm{T2}\)我不到啊,但......
  • CW信号的正交解调
    1.CW信号  CW可以叫做等幅电报,它通过电键控制发信机产生短信号"."(点)和长信号"--"(划),并利用其不同组合表示不同的字符,从而组成单词和句子。  CW信号可以看作一种幅度调制信号,类似于幅移键控(2ASK信号)其携带的信息保存在其幅度中,通过改变载波的幅度来实现基带数据的传输。其函......
  • ACwing 1524. 最长回文子串
    ACwing1524.最长回文子串因为这个题的数据范围只有1000,所以能O(n)枚举,枚举回文子串的中点,然后向两边延展,看看极限长度是多少,注意每次要区分奇数长度字串和偶数长度字串,两种的计算方式不一样。#include<iostream>#include<cstdio>#include<cstdlib>intmain(){ std::s......
  • 12.19 CW 模拟赛 T1. 烟花
    思路转化题意移步赛时记录详细题解见题解下载好的那么主要问题仍然是怎样做才能扔掉后效性,乍一看是不可能的,但是我们可以慢慢的考虑首先我们需要利用有效时间段\(\leq500\)这个条件,我们考虑建出每种选择的情况,再按照树上的仇恨关系建出图具体的,对于每一种\([j......
  • 12.19 CW 模拟赛 T2. 数
    思路赛时读错题了,虽然说读对了不一定能做出来,但是还是比较可惜首先阐述一下题意,对\(S\)数组进行插入和删除操作,每次询问让你用\(T\)中的质数组合出\(x\),然后将\(S\)中的数乘以\(x\)之后求最多的完全立方数个数那么显然的,我们对于每一个数,都可以拆成质......