首页 > 其他分享 >CSP-S模拟10

CSP-S模拟10

时间:2022-09-24 20:22:28浏览次数:48  
标签:rt 10 return int TP while CSP 模拟

T1.欧几里得的噩梦

第一眼,这不是线性基板子题吗。但是值域是\(2^{5e5}\),但是我们发现它的一个神奇性质,一个数的二进制中只有两个一。我们定义高位为x,低位为y。如果线性基中\(p[x]\)空,直接插入,令\(p[x]=y\);如果非空,x这一位被消掉,令\(x=p[x]\),如果x这时小于y就交换一下,因为线性基的构造是从高到低的。我们发现当这个数不能被插入时当且仅当有一个时刻\(x=y\)。这样暴力跳的时间复杂度不能保证,但是数据太水了,基本和正解一个速度。但是我们还是需要优化的,发现\(x=p[x]\)的状态为一棵树,而且这个关系是可传递的,并且如果存在某一时刻\(x=y\),那么之后这些位的p相同。所以这启发我们用并查集维护,每次\(find\)它们的最低位,看是否相等,如果相等,说明异或和为0。

代码
#define sandom signed
#define fre(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#include <bits/stdc++.h>
#define re register int 
using namespace std; int wrt[20], TP;
const int Z = 5e5 + 10; const int mod = 1e9 + 7; typedef long long ll;
inline int read() { int x = 0, f = 0; char c = getchar(); while (!isdigit(c)) f |= c == '-', c = getchar(); while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; }
inline void write(int x) { TP = 0; if (x < 0) putchar('-'), x = -x; while (x >= 10) wrt[++TP] = x % 10, x /= 10; wrt[++TP] = x; while (TP) putchar(wrt[TP--] | 48); putchar(' '); }
inline int qpow(int b) { ll res = 1; while (b--) res = res * 2 % mod; return res; }

int n, m, ans[Z], tot;
int p[Z];
inline int find(int x) { return x == p[x] ? x : p[x] = find(p[x]); }
inline bool insert(int x, int y)
{
    x = find(x), y = find(y);
    if (x == y) return false;
    if (x < y) swap(x, y);
    p[x] = y; return true;
}

sandom main()
{
    n = read(), m = read();
    for (re i = 0; i <= m; i++) p[i] = i;
    for (re i = 1; i <= n; i++) 
    {
        int op = read(), x = read(), y = 0;
        if (op == 2) y = read();
        if (insert(x, y)) ans[++tot] = i;
    }
    write(qpow(tot)), write(tot), putchar('\n');
    for (re i = 1; i <= tot; i++) write(ans[i]);
    return 0;
}

T2.清扫

考试只打了菊花图的,但是考后发现只需要对此拓展一下,对于每一个节点都判断一下就可以了。但是CD大佬有了更加简洁、通俗的方法。将贪心转化为方程问题。对于一棵子树,它的叶子节点中要么两两配对,两个叶子节点分别减1,根节点减1;要么一个叶子节点与子树外的一个叶子节点配对,叶子节点减1,根节点减1。我们设\(x\)为第一种情况的操作数,\(y\)为第二种情况的操作数。定义\(sum\)为子树的石子和(不包括自己)。则有方程组

\[2x+y=sum[rt] \\ x+y=a[rt] \\ \]

显然方程有解要满足\(x,y>=0\),同时还需要规定一个上界,即为\(max[rt]<=a[rt]\)(\(max[rt]\)为子树中最大的\(sum\)),因为超过了的话,显然父亲根本不够减完儿子。对于每一个非叶子节点,进行这样的处理,并把节点的石子数减去\(x,y\)的开销,作为新的叶子节点,向上回溯。最后需要判断根节点的石子数是否为0。细节:根节点的度数大于1,不然就作为叶子了。

代码
#define sandom signed
#define fre(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#include <bits/stdc++.h>
#define re register int 
using namespace std;
const int Z = 1e5 + 10;
inline int read() { int x = 0, f = 0; char c = getchar(); while (!isdigit(c)) f |= c == '-', c = getchar(); while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; }
inline int max(int a, int b) { return a > b ? a : b; } inline int min(int a, int b) { return a < b ? a : b; }

int n, m, k, ans;
vector <int> e[Z];
int a[Z], root;
int sum[Z], siz[Z];
bool dfs(int rt, int fa)
{
    if (e[rt].size() == 1) { sum[rt] = a[rt]; return true; }//叶子节点
    for (re i = 0; i < e[rt].size(); i++)
    {
        int son = e[rt][i];
        if (son == fa) continue;
        if (!dfs(son, rt)) return false;
        sum[rt] += sum[son];
        siz[rt] = max(siz[rt], sum[son]);
    }
    if (siz[rt] > a[rt]) return false;
    int x = sum[rt] - a[rt], y = 2 * a[rt] - sum[rt];
    sum[rt] = y;//将它作为叶子节点上传
    return x >= 0 && y >= 0;
}

sandom main()
{
    n = read();
    for (re i = 1; i <= n; i++) a[i] = read();
    if (n == 2) { a[1] == a[2] ? puts("YES") : puts("NO"); return 0; }
    for (re i = 1; i < n; i++)
    {
        int x = read(), y = read();
        e[x].push_back(y), e[y].push_back(x);
    }
    for (re i = 1; i <= n; i++) if (e[i].size() > 1) { root = i; break; }
    if (dfs(root, 0) && sum[root] == 0) puts("YES");
    else puts("NO");
    return 0;
}

T3.购物

这么水的题,我竟然没有做!!!结论题,但是证明是难点。先说结论:对于某一个价格\(w\),k的取值范围是\([\lceil \frac{w}{2}\rceil,w ]\)。按\(a\)排序后,定义\(s[i]\)为a的前缀和。对于其中一个\(a[i]\)的加入,新扩展的区间最远将到\(s[i]\),中间部分要么连续,要么只在\([s[i-1],\frac{a[i]}{2}]\)有空隙,要么连续,对于\([\frac{a[i]}{2}, s[i]]\)一定可以被覆盖。
首先明确:1式\([\frac{a[i]}{2}, a[i]]\)以及2式\([\frac{s[i]}{2}, s[i]]\)一定可以覆盖,3式\([1,s[i-1]]\)以及处理完,默认全部覆盖。需证明\([\frac{a[i]}{2}, s[i]]\)一定可以覆盖。
证明:假设前\(i-1\)个已经处理好,把问题看作两条线段的覆盖问题。分情况讨论:
1.3式包含1式,此时有\(\frac{a[i]}{2}<a[i]<s[i-1]\quad \because s[i]=s[i-1]+a[i]\quad \therefore 2a[i]< s[i]< 2s[i-1]\quad \therefore \frac{a[i]}{2}< a[i]< \frac{s[i]}{2}< s[i-1]< s[i]\),因为\(s[i-1]\)前已经处理完,且2式与\(s[i-1]\)相交,得证。覆盖连续。
2.3式与1式相交,此时有\(\frac{a[i]}{2}<s[i-1]<a[i]\quad \because s[i]=s[i-1]+a[i]\quad \therefore 2s[i-1]< s[i]< 2a[i]\quad \therefore \frac{a[i]}{2}< s[i-1]< \frac{s[i]}{2}< a[i]< s[i]\),因为1式与2式相交,得证。覆盖连续。
3.3式与1式分离,此时有\(s[i-1]<\frac{a[i]}{2}<a[i]\quad \because s[i]=s[i-1]+a[i]\quad \therefore 2s[i-1]< s[i]< 2a[i]\quad \therefore \frac{a[i]}{2}< s[i-1]< \frac{s[i]}{2}< a[i]< s[i]\),因为1式与2式相交,得证。只有\((s[i-1], \frac{a[i]}{2})\)断层。
证毕,开始贪心。

代码
#define sandom signed
#define fre(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#include <bits/stdc++.h>
#define re register int 
#define int long long 
using namespace std; int wrt[20], TP;
const int Z = 1e5 + 10;
inline int read() { int x = 0, f = 0; char c = getchar(); while (!isdigit(c)) f |= c == '-', c = getchar(); while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; }
inline void write(int x) { TP = 0; if (x < 0) putchar('-'), x = -x; while (x >= 10) wrt[++TP] = x % 10, x /= 10; wrt[++TP] = x; while (TP) putchar(wrt[TP--] | 48); putchar('\n'); }
inline int max(int a, int b) { return a > b ? a : b; } inline int min(int a, int b) { return a < b ? a : b; }
inline int lowbit(int x) { return x & (-x); }

int n, m, k, ans;
int a[Z];

sandom main()
{
    fre(test, test);
    n = read();
    for (re i = 1; i <= n; i++) a[i] = read();
    sort(a + 1, a + 1 + n);
    int sum = 0;
    for (re i = 1; i <= n; i++)
    {
        int j = (a[i] - 1) / 2 + 1;
        if (j <= sum) ans += a[i];//相交
        else ans += sum + a[i] - j + 1;//断层
        sum += a[i];//维护前缀和
    }
    cout << ans;
    return 0;
}

T4.ants

回滚莫队板子题。permu的加强版。但是当时用普通莫队加山海经水过了,这次被卡了,不仅如此,由于我的莫队没有排序……,喜提20分。由于是板子,直接上代码。

代码
#define sandom signed
#define fre(x, y) freopen(#x ".in", "r", stdin), freopen(#y ".out", "w", stdout);
#include <bits/stdc++.h>
#define re register int 
using namespace std; int wrt[20], TP;
const int Z = 1e5 + 10;
inline int read() { int x = 0, f = 0; char c = getchar(); while (!isdigit(c)) f |= c == '-', c = getchar(); while (isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return f ? -x : x; }
inline void write(int x) { TP = 0; if (x < 0) putchar('-'), x = -x; while (x >= 10) wrt[++TP] = x % 10, x /= 10; wrt[++TP] = x; while (TP) putchar(wrt[TP--] | 48); putchar('\n'); }
inline int max(int a, int b) { return a > b ? a : b; } inline int min(int a, int b) { return a < b ? a : b; }

int n, m, k, ans[Z];
int be[Z], p[Z], d[Z];
struct ant
{
    int l, r, id;
    friend bool operator <(ant A, ant B)
    {
        if (be[A.l] == be[B.l]) return A.r < B.r;//保证同一块内右端点只扩展
        return be[A.l] < be[B.l];//分块讨论
    }
}; ant que[Z];
int L[Z], R[Z];
int l, r, res, top;
struct delte { int a, b, c, d, e; }; delte stk[Z];
inline void add(int x, bool op)
{
    L[x] = R[x] = x;
    if (L[x - 1]) L[x] = L[x - 1];
    if (R[x + 1]) R[x] = R[x + 1];
    if (op) stk[++top] = delte{L[x], R[L[x]], R[x], L[R[x]], x};
    R[L[x]] = R[x], L[R[x]] = L[x];
    res = max(res, R[x] - L[x] + 1);
}
inline void del(delte x) { R[x.a] = x.b, L[x.c] = x.d, L[x.e] = R[x.e] = 0; }
inline int violent(int l, int r)//在同一块内暴力扫
{
    int ans = 1, cnt = 1;
    for (re i = l; i <= r; i++) d[i] = p[i];
    sort(d + l, d + r + 1); d[l - 1] = -1;
    for (re i = l; i <= r; i++) 
    {
        if (d[i] == d[i - 1] + 1) cnt++;
        else cnt = 1;
        ans = max(ans, cnt);
    }
    return ans;
}

sandom main()
{
    n = read(), m = read(); int t = sqrt(n);
    for (re i = 1; i <= n; i++) be[i] = (i - 1) / t + 1;
    for (re i = 1; i <= n; i++) p[i] = read();
    for (re i = 1; i <= m; i++) que[i].l = read(), que[i].r = read(), que[i].id = i;
    sort(que + 1, que + 1 + m);
    for (re i = 1; i <= m; i++)
    {
        ant q = que[i];
        if (be[q.l] != be[que[i - 1].l])//进入下一块清空
        {
            for (re i = 1; i <= n; i++) L[i] = R[i] = 0;
            r = min(t * be[q.l], n), l = r + 1; res = 0;
        }
        if (be[q.l] == be[q.r]) ans[q.id] = violent(q.l, q.r);//同一块暴力扫
        else 
        {
            while (r < q.r) add(p[++r], 0);//持续扩展
            int tmp = res;
            while (l > q.l) add(p[--l], 1);//扩展完撤销
            ans[q.id] = res; res = tmp;
            while (top) del(stk[top--]), l++;//回滚撤销
        }
    }
    for (re i = 1; i <= m; i++) write(ans[i]);
    return 0;
}

警钟敲响::不要4道题共用一个cpp,不要编译错文件,不要交错代码,交代码之前请检查CE情况!!!

标签:rt,10,return,int,TP,while,CSP,模拟
From: https://www.cnblogs.com/sandom/p/16726400.html

相关文章

  • CSP-S模拟10
    体活就是用来上体育的~~~Cat到操场上跑了n圈,6:00~6:25,并且边跑边唱歌,就是那首我最喜欢的"世界问,你是谁,来自哪……"好像路上有人因此回头多看了两眼,今天的云好美,一路上的老......
  • 力扣1095——山脉数组中查找目标值
    1095.山脉数组中查找目标值难度困难(这是一个 交互式问题 )给你一个 山脉数组 mountainArr,请你返回能够使得 mountainArr.get(index) 等于 target 最小 的......
  • 9.24-CSP-S模拟10
    T1欧几里得的噩梦一眼线性基题,可以证明在模拟线性基插入时,任何时候当前数的为1的位都不会超过二,于是模拟的做法就很显然了。但是这显然复杂度还是错的,赛时百分之八十的人......
  • Downie 4 for Mac中文版安装包(最好用的视频下载软件)V4.5.10直装版
    DownieforMac是一款MacOS平台上一款好用的视频下载工具,轻松从数千个不同的网站下载视频。支持youtube等主流网站视频,最大的特点最是支持网站多且可以多点同时下载,只需粘......
  • 2022NOIP前模拟赛订正情况
    √表示已订正,×表示不在能力范围之内,空表示未订正日期ABCD订正地址2022.9.3√√√×https://www.luogu.com.cn/contest/828672022.9.7√××ht......
  • 10、整合Mybatis框架
    mybatis中文文档:https://blog.csdn.net/qq_41182402/article/details/121281405UserMapper.xmlsql语句点击查看代码<?xmlversion="1.0"encoding="UTF-8"?><!DOC......
  • 200天1000题 (DAY 8)
    200天1000题(DAY8)目前总题数:36目前CF分数:1336(+11)今天打了一下CFRound#822(DIV2)手速比以前快,过了3个题,D想到一个双指针贪心的写法,但实现出来的代码有漏洞,疯狂WA......
  • ASEMI快恢复二极管6A10参数,6A10规格,6A10封装
    编辑-ZASEMI快恢复二极管6A10参数:型号:6A10最大重复峰值反向电压(VRRM):1000V最大RMS电桥输入电压(VRMS):700V最大直流阻断电压(VDC):1000V最大平均正向整流输出电流(IF):6A峰值......
  • [总结]2022.9.24 挖土机杯 CSP-J 组模拟赛 R1
    [总结]2022.9.24挖土机杯CSP-J组模拟赛R1P1赛时情况看到T1,显然是道白给。但我想了一会。依旧先把题目读完。T2有点模拟的样子,但又有点简单;T3显然dp;T4连乱搞都不会......
  • CF1310C Au Pont Rouge 解题报告
    题意翻译给出一个长度为\(n\)的字符串\(S\)以及整数\(m,k\)。对于一个把\(S\)分割成非空的\(m\)段的一个方案,我们用这个方案中分割出的字典序最小的一个串代表......