『模拟赛』信友队2024CSP-S第二轮(复赛)模拟赛

Rank

意外地好

image

A. 坦白

签。

首先对 \(m=0\) 很好求,正着跑一遍就行。接着考虑 \(m\lt 0\) 时什么时候遗忘会更优。发现是 \(\oplus\) 操作,因此答案为偶时(即事件为奇时)遗忘会使答案 +1。为判断是否比原先优,我们提前处理出后缀和即可。这题关键在想出一个性质,\(m=i\) 是由 \(m=i-1\) 时的最优解转移来的,即遗忘的顺序对答案没有影响,那么直接正着跑一遍找最优答案即可。然后容易得出事件数量为奇时 \(m=n\) 的答案为 1,为偶时答案为 0,然后随着 \(m\) 的下降我们跑完从以这两个值为起点倒着不断 +2 知道最大值然后重复即可。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x) ++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x) --)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
    lx x = 0, f = 1; char ch = getchar();
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
const int Ratio = 0;
const int N = 3e5 + 5;
int n;
int sum[N], mus[N];
string s;
stack<int> st;
namespace Wisadel
{
    short main()
    {
        freopen("confess.in", "r", stdin) , freopen("confess.out", "w", stdout);
        int T = qr;
        while(T--)
        {
            cin >> s; n = s.size(); s = " " + s;
            mus[n + 1] = 0;
            fo(i, 1, n)
                if(s[i] == '+') sum[i] = sum[i - 1] + 1;
                else sum[i] = sum[i - 1] - 1;
            fu(i, n, 1)
                if(s[i] == '+') mus[i] = mus[i + 1] + 1;
            	else mus[i] = mus[i + 1] - 1;
            printf("%d ", sum[n]);
            int now = 0, tim = 0, fla = 0, maxx = sum[n];
			fo(i, 1, n)
            {// 跑最大值
                if(now % 2 == 0 && now + 1 + mus[i + 1] > maxx)
                {
					now++, tim++;
                    maxx = now + mus[i + 1];
                    if(i == n) fla = 1;
                    printf("%d ", now + mus[i + 1]);
                }
                else if(s[i] == '+') now++;
                else now--;
			}
            // 分情况跑完剩下的
            if(n % 2 == 0)
            {
                int zc = 0, mit = 0;
                while(now < 0 || zc < now)
                {
                    st.push(zc), mit++;
                    if(now >= 0) zc += 2;
                    else now += 2;
                }
                while(mit + tim < n) st.push(now), mit++;
                while(st.size()) printf("%d ", st.top()), st.pop();
            }
            else
            {
                int zc = 1, mit = 0;
                while(now < 0 || zc < now)
                {
                    st.push(zc), mit++;
                    if(now >= 0) zc += 2;
                    else now += 2;
                }
                while(mit + tim < n) st.push(now), mit++;
                while(st.size()) printf("%d ", st.top()), st.pop();
            }
            puts("");
		}
        return Ratio;
	}
}
int main(){return Wisadel::main();}

B. 秘密

不难,也算是签。

首先比较一眼的是两边往中间跑,拿到线索往两边跑是很优的,那么关键就来到了第一个拿到线索的人如何行动。手模发现站着不动总不比往左往右更优的那一个优,所以就化简成只有两种情况了。首先第一段(只有一个人有线索时)是一定要跑完的,跑完之后对于任意相邻的有线索向无线索人传递的时间都是 \(\frac{dis_{u,v}}{2}\) 的,把全部时间加和后合并,应该是 $\frac{第一个有线索的人到最另一端的距离}{2} $,那么答案就是传递到两侧较大的那一个。用 set 维护每个人的坐标,枚举两种情况的答案取优即可。

记得特殊处理第一个有线索的人是边界的情况。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x) ++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x) --)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
    lx x = 0, f = 1; char ch = getchar();
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
const int Ratio = 0;
const int N = 2e5 + 5;
int n, m;
set<int> st;
set<int>::iterator it1, it2;
namespace Wisadel
{
    short main()
    {
        freopen("secret.in", "r", stdin) , freopen("secret.out", "w", stdout);
        n = qr, m = qr;
		fo(i, 1, n)
        {
            int a = qr;
            st.insert(a);
        }
        fo(i, 1, m)
        {
            char op; cin >> op; int x = qr;
            if(op == '+') st.insert(x);
            else if(op == '-') st.erase(x);
            else
            {
                int fir, ed;
                it1 = st.begin(); fir = *it1;
                it1 = st.end(); it1--; ed = *it1;
                it1 = it2 = st.lower_bound(x);
                double ans, zc1, zc2;
                if(it1 == st.begin())// 最左
                    ans = 1.0 * (ed - x) / 2;
                else
                {
                    it1--, it2++;
                    if(it2 == st.end())// 最右
                        ans = 1.0 * (x - fir) / 2;
                    else
                    {// 中间,向左向右取优
                        zc1 = 1.0 * (*it1 - fir) / 2;
                        zc2 = 1.0 * (ed - x) / 2;
                        ans = 1.0 * (x - *it1) / 2 + max(zc1, zc2);
                        zc1 = 1.0 * (x - fir) / 2;
                        zc2 = 1.0 * (ed - *it2) / 2;
                        ans = min(ans, 1.0 * (*it2 - x) / 2 + max(zc1, zc2));
                    }
                }
                printf("%.2lf\n", ans);
            }
        }
        return Ratio;
	}
}
int main(){return Wisadel::main();}

C. 潜力值

逆天 dXqwq csp-s 放 GF 题。

赛时由于边打边摆只打了全排列的 10pts

D. 括号

结论题。

赛时由全部匹配的括号序列启发,发现最多可以配对 \(\lfloor{}\frac{匹配个数}{2}\rfloor{}\) 个,原因是先手玩家首次取一种括号,后手取与之不同的括号,最多可以取 \(\lceil{}\frac{匹配个数}{2}\rceil{}\) 个那种括号,因此只剩 \(\lfloor{}\frac{匹配个数}{2}\rfloor{}\) 个给先手选。而一种括号严格多的序列,如 ()(()))))),则先手一定能配对 \(\lceil{}\frac{匹配个数}{2}\rceil{}\) 个。那么思路是将整个形如 ()(()))))(())()(((())() 的序列拆成 ()(()))))(())()(((())() 三段,第一、三段和在一起看,求出最后结果应该是 \(\lceil{}\frac{ans_1+ans_3}{2}\rceil{}+\lfloor{}\frac{ans_2}{2}\rfloor{}\),但是只有 75pts。如果有大蛇能给出反例请评论留言,感激不尽。

点击查看代码(75pts)
#include<bits/stdc++.h>
#define fo(x, y, z) for(register int (x) = (y); (x) <= (z); (x) ++)
#define fu(x, y, z) for(register int (x) = (y); (x) >= (z); (x) --)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
    lx x = 0, f = 1; char ch = getchar();
    for(; ch < '0' || ch > '9'; ch = getchar()) if(ch == '-') f = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ 48);
    return x * f;
}
#undef lx
#define qr qr()
const int Ratio = 0;
const int N = 2e5 + 5;
int n;
string s;
stack<int> st;
namespace Wisadel
{
    short main()
    {
        freopen("bracket.in", "r", stdin) , freopen("bracket.out", "w", stdout);
        int T = qr;
        while(T--)
        {
            cin >> s;
            n = s.size();
            s = " " + s;
            while(st.size()) st.pop();
            int ans = 0, s1 = 0, s2 = 0, l = 0, r = n + 1;
            fo(i, 1, n) if(s[i] != ')'){l = i; break;}
            fu(i, n, 1) if(s[i] != '('){r = i; break;}
            s = s.substr(l, r - l + 1);
            n = s.size();
            s = " " + s;
            fo(i, 1, n)
            {
                if(s[i] == '(') st.push(i), s1++;
                else
                {
                    s2++;
                    if(st.size()) st.pop(), ans++;
                }
            }
            while(st.size()) st.pop();
            if(s1 == s2) ans = ans / 2;
            else
            {
                int z1 = 0, z2 = 0, now = 0, pzuo = 0, pyou = 0, canl = 1, canr = n;
                fo(i, 1, n)
                {
                    if(s[i] == '(') st.push(i), z1++;
                    else
                    {
                        z2++;
                        if(st.size()) st.pop(), now++;
                        else canl = i + 1, pzuo = now;
                    }
                }
                while(st.size()) st.pop();
                z1 = 0, z2 = 0, now = 0;
                fu(i, n, 1)
                {
                    if(s[i] == ')') st.push(i), z2++;
                    else
                    {
                        z1++;
                        if(st.size()) st.pop(), now++;
                        else canr = i - 1, pyou = now;
                    }
                }
                int zc = ans - pzuo - pyou;
                ans = zc / 2 + (pzuo + pyou + 1) / 2;
            }
            printf("%d\n", ans);
        }
        return Ratio;
	}
}
int main(){return Wisadel::main();}

正解需要“足够好的观察力”,结论没什么技术含量,直接挂了。

image

本来想着是打着玩,然后变成了玩着打。

T1 T2 确实是玩着玩着就出来了,然后 T3 直接整不会了,憋了好久决定跳过,然后 T4 一直猜,猜过了大样例,拿了 75pts,还挺好。

感觉没什么很强的人在打信友队啊,这难度大蛇们不应该直接 AK 了?现在还是只有两个人过 T3。

一天打三场模拟赛确实累,下次还打。


完结撒花~

没图了,挂个丁真

image

posted @ 2024-10-20 16:58  DrRatio  阅读(177)  评论(0编辑  收藏  举报