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

CSP-S模拟8

时间:2022-09-27 21:59:40浏览次数:48  
标签:int re while freopen getchar CSP 模拟 define

全是\(JOI\)的题……为什么不做本民族的题(恼)

T1.选举

原以为是一道神奇贪心,所以写了\(O(n)\)的转移,但是发现\(n<=500\),这……都不用跑都知道假了。好吧,是一道dp——我们把n个州分为A、B、C(分别表示只赢得选票、又赢得选举、啥也没得到)。\(dp[i][j]\)定义为前\(i\)个州,得到了\(j\)个协助者。显然如果已知了需要\(k\)个\(B\)州,那么一定先在这\(k\)个州演讲,在从剩下的州里选几个\(A\)州演讲,每一个州的时间都是\(\frac{a}{k+1}\)。外层枚举想要得到几个协助者,我们先不考虑\(A\)州,只\(O(n^2)\)处理与\(B\)州有关的\(dp\),先选够\(B\)州,那么显然只需要在剩下的\(A、C\)州里选最小的几个作为\(A\)州即可。

代码
#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 = 520; 
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; }

int n, m, k;
struct vote { int a, b; }; vote c[Z], d[Z];
inline bool cmp1(vote A, vote B) { return A.a == B.a ? A.b < B.b : A.a < B.a; }//按a排序
inline bool cmp2(vote A, vote B) { return A.b == B.b ? A.a < B.a : A.b < B.b; }//按b排序
double ans = 1e9, res;
double dp[Z][Z];
inline void init() { for (re i = 0; i <= n; i++) for (re j = 0; j <= n; j++) dp[i][j] = 1e9; }

sandom main()
{
    n = read(), k = read();
    for (re i = 1; i <= n; i++)
    {
        c[i].a = read(), c[i].b = read();
        if (c[i].b == -1) c[i].b = 1e9;
    }
    sort(c + 1, c + 1 + n, cmp2);
    for (re t = 0; t <= k; t++)//枚举选几个协助者
    {
        init(); dp[0][0] = 0;
        for (re i = 1; i <= n; i++)//前i个州
            for (re j = 0; j <= min(i, t); j++)//得到了j个协助者
            {
                dp[i][j] = dp[i - 1][j] + 1.0 * c[i].a / (t + 1);//不要协助者
                if (j && c[i].b < 1e9) dp[i][j] = min(dp[i][j], dp[i - 1][j - 1] + 1.0 * c[i].b / j);//得到协助者
            }
        for (re i = t; i <= k; i++)//已经不需要协助者,贪心选最小的A
        {
            for (re j = 1; j <= n; j++) d[j] = c[j];
            sort(d + i + 1, d + n + 1, cmp1); res = 0;
            for (re j = i + 1; j <= k; j++) res += 1.0 * d[j].a / (t + 1);
            ans = min(ans, dp[i][t] + res);
        }
    }
    printf("%.10lf\n", ans);
    return 0;
}

T2.港口设施

我们把每一个集装箱覆盖的时间看做一个线段,那么当两个线段相交时,它们会产生矛盾,不能放在一个栈里,联想到关押罪犯。所以用扩展域并查集,当产生环时无解,否则因为各连通块之间相互独立,所以最后的答案就是\(2^{tot}\)(tot为连通块的数量)。这样建图是\(O(n^2)\),显然不行,其实有一个问题,对于一个连通块内的点,我们建了很多没有用的边,为了判无解只需要保证其中最小的一个环存在即可,其他的如果已知在一个连通块里就不再考虑。
Talking is easy, but…code is not。首先按桶的顺序遍历,当遇到左端点就入栈,遇到右端点,意味着从左端点到现在的中间的线段与它有交叉,我们需要分别连边,并把这个点删除,但是发现这不是从栈中间删除了吗。所以考虑用链表维护(或者并查集)。但这个时间复杂度还是不行,我们考虑上述所说的,有很多边有必要连,但是对答案没有贡献。我们对于已可以确定颜色的点的连续集合,只和其中一个连边,这样就大大减少了连边数量。这个可以用一个数组\(jump\)来维护,表示下一个可能不同色的点——对于一些点,如果和同一条线段相交,说明同色,那么把他们看成一个点,更新\(jump\),但是有一个细节,不能全部跳过,对于与它相交的线段,至少要连一个,这样才能保证正确性。

代码
#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 = 2e6 + 10; const int mod = 1e9 + 7;
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, ans = 1;
struct DSU
{
    int dad[Z];
    inline void init() { for (re i = 1; i <= m; i++) dad[i] = i; }
    inline int find(int x) { return x == dad[x] ? x : dad[x] = find(dad[x]); }
    inline bool un(int x, int y)
    {
        if (find(x) == find(y)) return false;
        dad[find(x)] = find(y + n), dad[find(y)] = find(x + n);
        return true;
    }
}; DSU nxt, graph;
int id[Z], jmp[Z], stk[Z], top, in[Z];
bool vs[Z];

sandom main()
{
    n = read(); m = n << 1;
    for (re i = 1; i <= n; i++) 
    {
        int a = read(), b = read();
        id[a] = id[b] = i;//桶排
    }
    nxt.init(), graph.init();
    for (re i = 1; i <= n; i++) jmp[i] = i + 1;
    for (re i = 1; i <= m; i++)
    {
        int j = id[i];
        if (!in[j]) stk[++top] = j, in[j] = top;//左端点
        else//右端点
        {
            int u = in[j], k;
            for (int v = nxt.find(u + 1); v <= top; v = k)//不断跳下一个需要连边的位置(从+1开始保证至少连一个)
            {
                if (!graph.un(j, stk[v])) { puts("0"); return 0; }
                k = nxt.find(jmp[v]);//找到一下个需要连边的位置
                jmp[v] = top + 1;//因为只需要保留最小的奇环(所以直接跳过)
            }
            nxt.dad[u] = u + 1;//把这个点删掉
        }
    }
    int tot = 0;
    for (re i = 1; i <= m; i++)
    {
        int j = graph.find(i);
        if (!vs[j]) tot++, vs[j] = 1;
    }
    for (re i = tot / 2; i >= 1; i--) (ans *= 2) %= mod;
    cout << ans << endl;
    return 0;
}

T3.幽深府邸

\(O(n^2)\)暴力只需要以每个点为出发点不断向两边扩展。但是我们发现到一个性质:对于已经被扩展玩的点\(j\),如果从\(i\)出发到达了\(j\),那么\(i\)的覆盖范围要至少大于\(j\),所以当我们走到已经被扩展过了的点时,直接取\(max\),就不再走重复的路。我们的暴力是开了个桶记录每一把钥匙,其实没有必要,我们只需要维护两个东西:左边第一个能拿到开启此房间的钥匙的位置,右边第一个能拿到开启此房间的钥匙的位置,显然再远的也被包含在内。那么根据此就可以快速得知能否到达。虽然加入了优化,但这仍然是暴力,所以为了防止被卡,我们\(random_shuffle\)一下,跑的飞起。

代码
#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 = 5e5 + 100;
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, q, ans;
int c[Z], L[Z], R[Z];
vector <int> key[Z];
int pos[Z], l[Z], r[Z], p[Z];
bool sol[Z];
void solve(int i)
{
    L[i] = R[i] = i; sol[i] = 1;
    bool flag = 1;
    while (flag)//还可以扩展
    {
        flag = 0;
        while (r[L[i] - 1] >= L[i] && r[L[i] - 1] <= R[i])//扩展左边
        {
            L[i]--, flag = 1;
            if (sol[L[i]]) L[i] = min(L[i], L[L[i]]), R[i] = max(R[i], R[L[i]]);
        }
        while (l[R[i] + 1] >= L[i] && l[R[i] + 1] <= R[i])//扩展右边
        {
            R[i]++, flag = 1;
            if (sol[R[i]]) L[i] = min(L[i], L[R[i]]), R[i] = max(R[i], R[R[i]]);
        }
    }
}

sandom main()
{
    n = read();
    for (re i = 1; i < n; i++) c[i] = read();
    for (re i = 1; i <= n; i++)
        for (re j = read(); j > 0; j--) key[i].push_back(read());
    for (re i = 0; i <= n; i++) pos[i] = 0;
    for (re i = 1; i <= n; i++)
    {
        l[i] = pos[c[i - 1]];//i房间左边第一个可以到达自己的位置
        for (re j = 0; j < key[i].size(); j++) pos[key[i][j]] = i;
    }
    for (re i = n; i >= 0; i--) pos[i] = n + 1;
    for (re i = n; i >= 1; i--)
    {
        r[i] = pos[c[i]];//i房间右边第一个可以到达自己的位置
        for (re j = 0; j < key[i].size(); j++) pos[key[i][j]] = i;
    }
    for (re i = 1; i <= n; i++) p[i] = i;
    random_shuffle(p + 1, p + 1 + n);
    for (re i = 1; i <= n; i++) solve(p[i]);
    q = read();
    while (q--)
    {
        int x = read(), y = read();
        if (y >= L[x] && y <= R[x]) puts("YES");
        else puts("NO");
    }
    return 0;
}

T4.长途巴士

蒟蒻、不会、鸽。

标签:int,re,while,freopen,getchar,CSP,模拟,define
From: https://www.cnblogs.com/sandom/p/16735922.html

相关文章

  • CSP-S模拟13排序 Xorum 有趣的区间问题 无聊的卡牌问题
    T1【构造+规律】:给你一个排列,要你求逆序对数量,把原序列的逆序对位置当成交换,进行任意排列使得最后序列升序。(n<=1000)一:排列的实质是id[i]=i的一一对应,问题互相转化会更简......
  • CSP202203_3
    CSP202203_3目录CSP202203_3题目思路Code题目计算资源调度器思路直接模拟,画个大致的分析图即可理清题目要求。一个区上有多个节点,一个应用有多个任务。一个任务只占......
  • CSP-S模拟13
    又是模拟退役的一天A.排序死因:输出没有让前面小于后面通过找规律发现交换两个数值相邻的一定可以原因是这样保证每次操作只减少一个逆序对code#include<bits/std......
  • CSP模拟13
    套路题不会。考虑重修一下。T1经过考后的采访,joke3579、gtm1514、Chen_jr、Muel_imj四个人考场上写的Checker都拍过了然后都挂了零。实际上从前往后扫,只要交换每个位置......
  • 做题记录整理dp13 P7914 [CSP-S 2021] 括号序列(2022/9/26)
    P7914[CSP-S2021]括号序列非常考思维的思维题(甚至做到了让全广西都恐惧(似乎广西连拿暴力分的人都没有))由于看了题解,所以这题相当于是在巨人的肩膀上做题了。。。而且......
  • Hbuilderx中mac链接android模拟器
    1、打开了mumu模拟器。2、hBuilderX=>运行=>abd路径设置=>只需要填写android模拟器端口7555(网易mumu模拟器对应的,每个模拟器有自己的,具体查看文档)3、./adbki......
  • CoCo和Tom是一对好拍档,他们两个经常相互比赛记忆能力。今天他们的比赛项目就是模拟万
    #include<stdio.h>main(){intyear,month;scanf("%d%d",&year,&month);switch(month){case1:case3:case5:case7:case8:case10:case12:printf......
  • 做题记录整理dp13 P5664 [CSP-S2019] Emiya 家今天的饭(2022/9/26)
    P5664[CSP-S2019]Emiya家今天的饭终于遇到一个我感觉在考场上有可做出来的题了。。。唯一想不到的就是最开始的容斥(也就是说还是看了题解。。。),如果容斥想到的话其他......
  • CSP-S模拟12
    喜欢写博客的前提是得会改题……好难啊如果明天能收到生日礼物,或者一句生日快乐的话,我会非常快乐的,并且祝福你rp++ A.开挂发现改变之后的得到的结果是唯一确定的,为了......
  • 42ed 2022/9/10&2021/9/17 纪中CSP.S组第一轮训练
    第一次(2022/9/10:陕西2020)得分70,不高不低,略有不足,因为还有一些题目的分能拿但没拿到,考试共进行了2h,原本应该是4h,仍然都能做完,还进行了两次检查首先是在选择题上,一道栽在......