首页 > 其他分享 >『模拟赛』多校A层冲刺NOIP2024模拟赛21

『模拟赛』多校A层冲刺NOIP2024模拟赛21

时间:2024-11-12 21:30:32浏览次数:1  
标签:ch uy 21 int qr 模拟 binom NOIP2024 define

Rank

别样的,不好评价,烂完了

image

A. 送信卒

签,我是唐氏。

为什么呢

image

题目没给最短路的定义,我赛时觉得最短路就是最短路径,于是直接 bfs 一遍随便加个 check 就做完了。当然过得那遍按我的思路来说是错的,然后我也发现了这一点,然后就改了,然后就 WA 了。总结:错误思路的错解是正确思路的正解,错误思路的正解是正确思路的错解。

bfs 太好理解了,没什么说的。但总感觉正确性有问题,不断加特判 corner cases 大概也不过不了题意的最短路不是最短路径的情况,所以还是记录一下题解做法。

二分 k 的大小,跑最短路 check,复杂度 \(\mathcal{O(n^2\log n)}\)。

话说我都多久没场上打出过 T1 题解做法了

点击查看代码(bfs)
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    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()
#define pii pair<int, int>
#define ppp pair<pii, pii>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 100 + 5;
const int mod = 1e9 + 7;
int n, m;
int sx, sy, ex, ey;
int d[N][N];
pii f[N][N];
bool yz[N][N];
int xxx[5] = {0, -1, 0, 0, 1};
int yyy[5] = {0, 0, 1, -1, 0};
double s, k;
namespace Wisadel
{
    inline bool Wck(int x, int y, int id)
    {
        int tx = x + xxx[id], ty = y + yyy[id];
        if(tx && tx <= n && ty && ty <= m && d[tx][ty] != 1)
        {
            if(!yz[tx][ty]) return 1;
            else if((f[tx][ty].fi + f[tx][ty].se == f[x][y].fi + f[x][y].se + 1) && f[tx][ty].fi > f[x][y].fi + (id == 1 || id == 4)) return 1;
        }
        return 0;
    }
    inline void Wbfs(int x, int y)
    {
        queue<pii> q;
        yz[x][y] = 1;
        f[x][y] = M_P(0, 0);
        q.push(M_P(x, y));
        while(q.size())
        {
            int ux = q.front().fi, uy = q.front().se;
            q.pop();
            if(f[ux][uy].se + (max(uy, sy) - min(uy, sy)) > s) continue;
            fo(i, 1, 4)
            {
                if(Wck(ux, uy, i))
                {
                    if(i == 1 || i == 4)
                        f[ux + xxx[i]][uy + yyy[i]] = M_P(f[ux][uy].fi + 1, f[ux][uy].se);
                    else f[ux + xxx[i]][uy + yyy[i]] = M_P(f[ux][uy].fi, f[ux][uy].se + 1);
                    yz[ux + xxx[i]][uy + yyy[i]] = 1;
                    q.push(M_P(ux + xxx[i], uy + yyy[i]));
                }
            }
        }
    }
    short main()
    {
        freopen("msg.in", "r", stdin), freopen("msg.out", "w", stdout);
        n = qr, m = qr;
        sx = qr, sy = qr, ex = qr, ey = qr;
        fo(i, 1, n) fo(j, 1, m) d[i][j] = qr;
        cin >> s;
        Wbfs(ex, ey);
        k = (s - f[sx][sy].se) / (1.0 * f[sx][sy].fi);
        printf("%.3lf\n", k);
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// Now there's only one thing I can do
// Fight until the end like I promised to

B. 共轭树图

树形 dp + 计数。

前几天天天有卡特兰数直接被洗脑,上来看链的性质直接发现就是卡特兰数,然后多求了一个,然后挂 32pts。

设 \(f_{i,j}\) 表示点 \(i\) 向上能连深度不超过 \(j\) 祖先的方案数。考虑转移,发现子节点能连的祖先当前节点一定能连(除去当前节点),父节点连不了的子节点也一定不能连,那么子节点能连的数量实质上是父节点的数量加上它本身。而我们所设 \(f\) 完全可以等效将深度向上若干个,又根据乘法原理,每个子节点的子树方案数互不干扰,那么转移方程有:

\[f_{u,i}=\prod_{v\in subtree_u}\sum_{j=1}^i\ f_{v,j+1} \]

那么做完了,复杂度 \(\mathcal{O(n^2)}\)。

点击查看代码
// ubsan: undefined
// accoders
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    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()
#define pii pair<int, int>
#define ppp pair<pii, pii>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 3000 + 5;
const int mod = 998244353;
int n;
int hh[N], to[N << 1], ne[N << 1], cnt;
ll f[N][N], ans;
namespace Wisadel
{
    inline void Wadd(int u, int v)
    {
        to[++cnt] = v;
        ne[cnt] = hh[u];
        hh[u] = cnt;
    }
    void Wdfs(int u, int fa)
    {
        fo(i, 1, n) f[u][i] = 1;
        for(int i = hh[u]; i != -1; i = ne[i])
        {
            int v = to[i];
            if(v == fa) continue;
            Wdfs(v, u);
            ll zc = 0;
            fo(i, 1, n)
            {
                zc = (zc + f[v][i + 1]) % mod;
                f[u][i] = f[u][i] * zc % mod;
            }
        }
    }
    short main()
    {
        freopen("reflection.in", "r", stdin), freopen("reflection.out", "w", stdout);
        n = qr;
        memset(hh, -1, sizeof hh);
        bool task1 = 1, task2 = 1;
        fo(i, 1, n - 1)
        {
            int a = qr, b = qr;
            Wadd(a, b), Wadd(b, a);
        }
        Wdfs(n, 0);
        printf("%lld\n", f[n][1]);
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// Now there's only one thing I can do
// Fight until the end like I promised to

C. 摸鱼军训

不是很难想的思维题。场上只会暴力。

考虑一次询问 \(x,k\)。如果 \(k\gt n-x\),那么此时 \(x\) 一定已经被排到最后它原本应该的位置,\(ans=x\)。然后是一个比较 trick 的分类,设 \(x\) 原本位置前面有 \(s\) 个大于 \(x\) 的数。当 \(k\le s\) 时,可以容易想到这 \(k\) 个数会依次经过 \(x\),而 \(x\) 也就顺次向前移动了 \(k\) 个,故 \(ans=pre_x-k\)。而剩下的最后一种情况,即此时 \(x\) 后比 \(x\) 大的数依次归位时,我们会发现每次会被“卡”在 \(x\) 后第一个比 \(x\) 大的位置上,一共会这样卡 \(k-s\) 次。手模再次发现,这相当于是比 \(x\) 大的数按顺序第 \(k\) 个的位置向前移动 \(k\) 次,即 \(ans=search(k)-k\)。

发现线段树所需要的操作只有单点修改和查询第 \(k\) 个 1 的位置。我们直接将询问挂在 \(x\) 上倒序处理,处理完将当前 \(x\) 在原序列上标为 1,意思是比之后的 \(x\) 大。然后就做完了,查询直接线段树上二分,复杂度 \(\mathcal{O(n\log n)}\),代码很好写。

点击查看代码
#include<bits/stdc++.h>
#define fo(x, y, z) for(int (x) = (y); (x) <= (z); (x)++)
#define fu(x, y, z) for(int (x) = (y); (x) >= (z); (x)--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define lx ll
inline lx qr()
{
    char ch = getchar(); lx x = 0, f = 1;
    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()
#define pii pair<int, int>
#define ppp pair<pii, pii>
#define fi first
#define se second
#define M_P(x, y) make_pair(x, y)
#define P_B(x) push_back(x)
const int Ratio = 0;
const int N = 5e5 + 5, M = 3000 + 5;
const int mod = 998244353;
int n, m;
int a[N], pre[N];
vector<pii> q[N];
int v[N << 2];
int ans[N];
namespace Wisadel
{
    #define ls (rt << 1)
    #define rs (rt << 1 | 1)
    #define mid ((l + r) >> 1)
    inline void Wpushup(int rt){v[rt] = v[ls] + v[rs];}
    inline void Wupd(int rt, int l, int r, int x)
    {
        if(l == r){v[rt] = 1; return ;}
        if(x <= mid) Wupd(ls, l, mid, x);
        else Wupd(rs, mid + 1, r, x);
        Wpushup(rt);
    }
    inline int Wq(int rt, int l, int r, int k)
    {
        if(l == r) return l;
        if(v[ls] >= k) return Wq(ls, l, mid, k);
        return Wq(rs, mid + 1, r, k - v[ls]);
    }
    short main()
    {
        freopen("bubble.in", "r", stdin), freopen("bubble.out", "w", stdout);
        n = qr;
        fo(i, 1, n) a[i] = qr, pre[a[i]] = i;
        m = qr;
        fo(i, 1, m)
        {
            int k = qr, x = qr;
            q[x].P_B(M_P(k, i));
        }
        fu(i, n, 1)
        {
            for(pii kk : q[i])
                if(kk.fi > n - i) ans[kk.se] = i;
                else ans[kk.se] = max(Wq(1, 1, n, kk.fi), pre[i]) - kk.fi;
            Wupd(1, 1, n, pre[i]);
        }
        fo(i, 1, m) printf("%d\n", ans[i]);
        return Ratio;
    }
}
signed main(){return Wisadel::main();}
// Now there's only one thing I can do
// Fight until the end like I promised to

D. 神奇园艺师

向 Qyun 学会了,不知道今天晚上来不来得及改出来。

首先质因数拆分,发现每个质数是独立的,因此分开算,每个数只与指数有关。

一个重要结论:求出一个 \(x\) 使得 \(\sum_{i=1}^n\ |a_i-x|\) 最小的结果是中位数。这个手模一下很好出,但很重要,后面都围绕这个展开。

枚举每一个指数 \(num_i\) 作中间的数,然后枚举其左边有 \(a\) 个,右边有 \(b\) 个。如果 \(a\lt b\),说明当前中间的数在中位数左边,贡献是负的,然后组合数可以得出答案:

\[ans=-num_i\binom{i-1}{a}\binom{n-i}{b} \]

\(a\gt b\) 的情况同理,答案为:

\[ans=num_i\binom{i-1}{a}\binom{n-i}{b} \]

那么就得到了一个 \(\mathcal{O(n^3\log n)}\) 的做法,枚举质数,然后枚举每一项,然后分别枚举 \(a,b\)。

发现这样枚举两项是很不优的,考虑优化。先考虑 \(a\lt b\) 的情况,设 \(d=b-a\),那么对于每个 \(num_i\),答案有:

\[\begin{aligned}ans_i&=\sum_{d=0}^{\max(i,n-i)}\sum_{a=0}^i\ -num_i\binom{i-1}{a}\binom{n-i}{a+d}\\ &=\sum_{d=0}^{\max(i,n-i)}\sum_{a=0}^i\ -num_i\binom{i-1}{a}\binom{n-i}{n-i-a-d} \end{aligned}\ \]

然后什么范德蒙德卷积,原式为:

\[\sum_{i=0}\ \binom{n}{i}\binom{m}{s-a}=\binom{n+m}{s} \]

Qyun 讲了个生动的例子:\(n\) 个男人,\(m\) 个女人中选出 \(s\) 个人。这就很显然了。

然后答案就变成了:

\[ans=\sum_{d=0}^{\max(i,n-i)}\binom{n-1}{n-i-d} \]

这个式子就已经很优了,我们直接前缀和优化求组合数就可以在 \(\mathcal{O(n\log n)}\) 的复杂度内解决了!


其他的明天再说。

标签:ch,uy,21,int,qr,模拟,binom,NOIP2024,define
From: https://www.cnblogs.com/Ratio-Yinyue1007/p/18542558

相关文章

  • 多校A层冲刺NOIP2024模拟赛21
    多校A层冲刺NOIP2024模拟赛21\(T1\)A.送信卒\(90pts/100pts\)部分分\(90pts\)设最后的可能的最短路中左右共移动了\(d\)次,上下共移动了\(x\)次。则等价于求\(\min\{x_{i}k+d_{i}\}=s\)的解,观察到\(d\in[0,\min(\left\lceil\frac{nm}{2}\right\rce......
  • noip模拟11
    A送信卒考场上唐了,把方向搞反导致挂零。。。然后就是跑一边bfs,算出来最短路,并且记录横纵位移,就好了。好像也可以二分然后去跑djikstra。其实有个hack,会让我的代码在特定情况下不稳定地输出错解:1010115500000000000111111110011100000......
  • NOIP模拟赛 #10
    ALuogu6472猜结论。B有\(n\)堆硬币,每堆有\(3\)枚,第\(i\)堆硬币从上到下价值分别为\(a_i,b_i,a_i\)。取若干个硬币,要求每堆必须先取上面再取下面,求分别取\(1,2,3,\dots,k\)枚硬币时的最大价值和。\(1\len\le5\times10^6,\1\lek\le3n\)对于第\(i\)堆,......
  • [考试记录] 2024.11.12 noip模拟赛11
    T1使用\(bfs\)记录走到\(tx,ty\)的路径的横边和竖边的数量,然后取\(\max\)。这里取\(\max\)的原因是,找到的路径必须是最短路,当\(k\)取的小的时候竖边就会变多,所以这条路径就不一定是最短路了。#include<bits/stdc++.h>usingnamespacestd;#defineppair<int,int>i......
  • 20241112 模拟赛总结
    期望得分:100+100+0+10=210实际得分:100+80+0+10=190好困。。T1被硬控了很久。看着就像诈骗题,观察大样例发,答案就是\(a_1-a_2\),特判\(n=1\)的情况。证明的话,感觉就是后面的数,贡献成正数和负数应该是数量相同的,所以就抵消了,第一个数只能贡献成正数,第二个数只能贡献成负的。T......
  • 在通讯领域,特别是在自由空间光通信(Free Space Optics, FSO)通道模拟中,选择合适的模型需
    在通讯领域,特别是在自由空间光通信(FreeSpaceOptics,FSO)通道模拟中,选择合适的模型需要考虑模型对动态变化的光信号传播环境的适应性和预测能力。根据搜索结果,以下是一些可能适合通讯领域FSO通道模拟的模型:TACTiS-2:这是一个灵活的多变量概率时间序列预测模型,它简化了attenti......
  • 2024.11.12 NOIP模拟 - 模拟赛记录
    Preface一套烂题。T1一眼搬的CF(赛后十秒就找到原题了),只搬idea就算了,根本不设置部分分,大样例给的更是一坨(数据范围给的\(10^{15}\),121072121算什么大样例?),甚至最后的题解都是直接复制的洛谷。T2稍好,除了实数运算稍微恶心一点,其它都没什么。T3又是一大坨,不给SPJ都......
  • 20241112【NOIP】模拟
    如果上一场是本来都会做,但是因为题没读清楚和智障错误导致挂分后排名低,那么这一场就是纯纯脑瘫,以为题会很难,一点都没有深入思考过,结果暴力一分没挂,但是别人T1T2T3都切了,最后成了小丑......
  • 打卡信奥刷题(221)用C++信奥P1740[普及组/提高] Diamond A&B(1)
    DiamondA&B(1)题目背景由于本题较难,将本题拆做两题,分别为diamondA以及diamondB。本题为DiamondA。题目描述教主上电视了!这个消息绝对是一个爆炸性的新闻。一经传开,大街上瞬间就没人了(都回家看电视去了),商店打烊,工厂停业。大家都把电视机的音量开到最大,教主的声音......
  • 字符串函数strcpy.strcat.strcmp的应用和模拟实现
    strcpy的应用和模拟实现strcpy详解:先来看下官网对strcmp的介绍。绿色部分括号内为需要的两个参数.第一个char*destination指的是目标字符串的起始地址;第二个consetchar*source指的是要拷贝的字符串;最前面的char*strcpy表明返回类型为字符指针.(返回......