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

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

时间:2024-10-09 18:48:43浏览次数:7  
标签:ch 04 int zc 模拟 ans mod NOIP2024 fo

Rank

赤石场。

image

A. 02表示法

签。

若干天前在洛谷随到过,不过当时只看了眼讨论区就走了www 还好本来不是很难。

发现大体上是一个拆分二的幂的问题,从大到小枚举 2 的幂,判断有没有这个幂只用比较大小关系,然后再对指数做一个同样的操作,递归至不大于 2 为止,注意 \(2^1\) 不用输出 (1)

发现数据范围达到了惊人的 \(10^{180}\),不过它约等于 \(2^{598}\),也就是说对这做法没有影响,只是二的幂要用高精的形式体现。只用到了高精比较,高精乘低精和高精减三个操作,不是很难写。

点击查看代码
#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()
{
	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 fi first
#define se second
const int Ratio = 0;
const int N = 2e5 + 5;
const int mod = 1e9 + 7;
int pf[N], tot;
int s[600][200], a[200], zc[200];
string op, ss;
namespace Wisadel
{
    bool Wcmp(int a[], int b[])
    {
        if(a[0] != b[0]) return a[0] > b[0];
        fu(i, a[0], 1) if(a[i] != b[i]) return a[i] > b[i];
        return 1;
    }
    void Wp(int id, int b)
    {
        fo(i, 0, s[id][0]) a[i] = s[id][i];
        memset(zc, 0, sizeof zc);
        int x = 0, len = a[0];
        fo(i, 1, len)
        {
            zc[i] = a[i] * b + x;
            x = zc[i] / 10;
            zc[i] %= 10;
        }
        if(x) len++, zc[len] = x;
        zc[0] = len;
        fo(i, 0, len) s[id + 1][i] = zc[i];
    }
    void Wjian(int id)
    {
        fo(i, 1, s[id][0])
        {
            if(a[i] >= s[id][i]) a[i] -= s[id][i];
            else a[i + 1]--, a[i] = a[i] + 10 - s[id][i];
        }
        while(!a[a[0]]) a[0]--;
    }
    void Wpre()
    {
        s[0][0] = s[0][1] = 1;
        fo(i, 1, 598) Wp(i - 1, 2);
    }
    string Wdfsc(int x)
    {
        if(x == 0) return "0";
        string sss = "";
        bool tou = 1;
        fu(i, 12, 0)
        {
            if(x >= pf[i])
            {
                if(tou) tou = 0;
                else sss += "+";
                if(i == 1) sss += "2";
                else sss += "2(" + Wdfsc(i) + ")";
                x -= pf[i];
            }
        }
        return sss;
    }
    void Wdfs()
    {
        if(a[0] == 1 && a[1] == 1){ss += "2(0)"; return ;}
        if(a[0] == 1 && a[1] == 2){ss += "2"; return ;}
        bool tou = 1;
        fu(i, 598, 0)
        {
            if(Wcmp(a, s[i]))
            {
                if(tou) tou = 0;
                else ss += "+";
                if(i == 1) ss += "2";
                else ss += "2(" + Wdfsc(i) + ")";
                Wjian(i);
            }
        }
    }
    short main()
    {
        freopen("pow.in", "r", stdin) , freopen("pow.out", "w", stdout);
        Wpre();
        cin >> op;
        a[0] = op.size();
        fo(i, 1, a[0]) a[i] = (int)op[i - 1] - '0';
        fo(i, 1, a[0]) zc[i] = a[a[0] - i + 1];
        fo(i, 1, a[0]) a[i] = zc[i];
        pf[0] = 1;
        fo(i, 1, 12) pf[i] = pf[i - 1] * 2;
        Wdfs();
        cout << ss << endl;
        return Ratio;
    }
}
int main(){return Wisadel::main();}

B. 子串的子串

加强版 P6292

开场听到 5k 的赞叹后思维就被莫队固定住了,想不到什么很优的 add 操作,最后复杂度大概是 \(\mathcal{O(n^2q)}\) 的(?),拿到 70pts。

考虑正解。发现不带修,因此答案不变,我们可以提前处理出来。设 \(ans_{l,r}\) 表示 \(\left[l,r\right]\) 内本质不同子串个数。枚举串长和左端点,用求出每个串的哈希值,开一个 map 记录该串上次出现的左端点 \(las\),此时 \(\left[las,r\right]\) 显然出现了一个重复串,使 \(ans_{las,r}\) 减一。最后从一端开始枚举所有串,根据二维前缀和的求法可知:

\[ans_{l,r}=ans_{l+1,r}+ans_{l,r-1}-ans_{l+1,r-1}+1+ans_{l,r} \]

当然还有个更好理解的思路,如图:

image

相当于是 \(\left[l,r\right]\) 原本的限制,加上串 \(s_{l,r}\) 本身,然后加 \(ans_{l+1,r}\) 与 \(ans_{l,e-1}\) 时将 \(ans_{l+1,r-1}\) 多算了一遍,减去即可。然后就可以 \(\mathcal{O(1)}\) 查询了,总复杂度是 \(\mathcal{O(n^2+q)}\) 的。

int_R 打了 SAM 效率薄纱所有人%%%。

点击查看代码
#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;
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 fi first
#define se second
const int Ratio = 0;
const int N = 3000 + 5;
const int base = 233;
int n, m;
string s;
ull has[N], k[N];
unordered_map<ull, int> mp;
int ans[N][N];
namespace Wisadel
{
    ull Whash(int l, int r){return has[r] - has[l - 1] * k[r - l + 1];}
    short main()
    {
        freopen("substring.in", "r", stdin) , freopen("substring.out", "w", stdout);
        n = qr, m = qr;
        cin >> s; s = " " + s; k[0] = 1;
        fo(i, 1, n) has[i] = has[i - 1] * base + s[i], k[i] = k[i - 1] * base;
        fo(len, 1, n)
        {
            mp.clear();
            fo(l, 1, n - len + 1)
            {
                int r = l + len - 1;
                ull zc = Whash(l, r);
                ans[mp[zc]][r]--;
                mp[zc] = l;
            }
        }
        fu(l, n, 1) fo(r, l, n)
            ans[l][r] += ans[l + 1][r] + ans[l][r - 1] -ans[l + 1][r - 1] + 1;
        fo(i, 1, m) printf("%d\n", ans[qr][qr]);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

C. 魔法咒语

赛时想到了正反建两棵 trie 树但不知道怎么容斥计数于是止步 20pts。

忘了之前的套路,容斥不会就分讨,不重就不用容斥。我们建反向 trie 树时记录每一种字母节点的数量,然后遍历正向 trie 树的节点,考虑怎么计数。遍历其 26 种子节点,如果该节点没有某种字母的子节点,则此时拼接该字母开头的后缀时一定没有重复情况,那么令 \(ans+=cnt_{该字母}\) 即可。

发现当前缀串取到一个完整的串时,一定可以在其后补一个与最后一个字母相同的字母使其为新串,所以记录一下每个字母是否是某一个串的结尾,然后在上述判断为否的时候再进行判断即可。

但是这种计数局限于串可拆分的情况,对于一个单字母组成的串发现它不会被算入,而两个这样的串又显然能构成一个新串,因此输入时对于这种串直接特判即可。复杂度大概是 \(\mathcal{O(正向\ trie\ 树上节点数\times 26)}\) 的。

点击查看代码
#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()
{
	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 fi first
#define se second
const int Ratio = 0;
const int N = 4e5 + 5;
const int mod = 1e9 + 7;
int n, tot, oto;
string s[N];
int to[N][26], v[26], ot[N][26], yz[26], fla[26];
ll ans;
namespace Wisadel
{
    void Wins(string s)
    {
        int now = 0, len = s.size();
        fo(i, 0, len - 1)
        {
            int zc = s[i] - 'a';
            if(!to[now][zc]) to[now][zc] = ++tot;
            now = to[now][zc];
        }
    }
    void Wsni(string s)
    {
        int now = 0, len = s.size();
        fu(i, len - 1, 0)
        {
            int zc = s[i] - 'a';
            if(!ot[now][zc]) ot[now][zc] = ++oto, v[zc]++;
            now = ot[now][zc];
        }
    }
    short main()
    {
        freopen("magic.in", "r", stdin) , freopen("magic.out", "w", stdout);
        n = qr;
        fo(i, 1, n)
        {
            cin >> s[i];
            Wins(s[i]), Wsni(s[i]);
            yz[s[i][s[i].size() - 1] - 'a'] = 1;
            if(s[i].size() == 1 && !fla[s[i][0] - 'a']) ans++, fla[s[i][0] - 'a'] = 1;
        }
        fo(i, 1, tot) fo(j, 0, 25)
            if(!to[i][j]) ans += v[j];
            else if(yz[j]) ans++;
        printf("%lld\n", ans);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

D. 表达式

挺妙的一道题,赛时由于没开 long long 导致没拿到 15pts 暴力分。

这题用到了数据点分治,本来还以为没有题正解会是这玩意。首先对于 Subtask1,直接 \(\mathcal{O(nm)}\) 暴力即可,主要考虑其它的子任务。

发现其它的子任务的共性是模数拆成不互质的形式的个数后非常少也非常小,拆后最大的模数也只有 29,我们完全可以将其拆开分别计算对于不同模数的不同答案。而且加、乘和乘方都是支持取模运算的,那么就有 \(f(x)=f(x\mod p)\)。

我们可以直接暴力处理出 \(\left[0,p-1\right]\) 的所有函数值,用线段树维护,主要操作就是一个线段树合并的过程,而这个又非常简单,只用把左子树的函数值代到右子树的函数里求值即可。这样我们就得到了所有对拆开后的模数取模的答案,写出来就是这个:

\[\begin{cases} ans_1\equiv ans\pmod {p_1}\\ans_2\equiv ans\pmod{p_2}\\\vdots ans_n\equiv ans\pmod{p_n} \end{cases} \]

发现就是 crt 的基本形式,然后直接跑就完了。

点击查看代码
#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()
{
	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 pil pair<int, ll>
#define fi first
#define se second
const int Ratio = 0;
const int N = 2e5 + 5;
namespace Wistask1
{
    int n, m, mod;
    pii d[N];
    ll Wqp(ll x, int y)
    {
        ll res = 1;
        while(y)
        {
            if(y & 1) res = res * x % mod;
            x = x * x % mod;
            y >>= 1;
        }
        return res;
    }
    void Wwork(ll x)
    {
        fo(i, 1, n)
        {
            if(d[i].fi == 1) x = (x + d[i].se) % mod;
            else if(d[i].fi == 2) x = x * d[i].se % mod;
            else x = Wqp(x, d[i].se);
        }
        printf("%lld\n", x);
    }
    short main()
    {
        n = qr, m = qr, mod = qr;
        fo(i, 1, n)
        {
            string s; cin >> s;
            if(s[0] == '+') d[i].fi = 1;
            else if(s[0] == '*') d[i].fi = 2;
            else d[i].fi = 3;
            ll num = 0;
            fo(j, 1, s.size() - 1) num = num * 10 + s[j] - '0';
            d[i].se = num;
        }
        fo(i, 1, m)
        {
            int op = qr, x = qr;
            if(op == 1) Wwork(x);
            else
            {
                string s; cin >> s;
                if(s[0] == '+') d[x].fi = 1;
                else if(s[0] == '*') d[x].fi = 2;
                else d[x].fi = 3;
                ll num = 0;
                fo(j, 1, s.size() - 1) num = num * 10 + s[j] - '0';
                d[x].se = num;
            }
        }
        return Ratio;
    }
}
namespace Wvictoria
{
    int n, m, M;
    int yz[100], tot, pri[26], mod[26], gs;
    pil d[N];
    struct rmm
    {
        int mod;
        ll Wqp(ll x, ll y)
        {
            ll res = 1;
            while(y){if(y & 1) res = res * x % mod; x = x * x % mod; y >>= 1;}
            return res;
        }
        int f[N << 2][30];
        #define ls (rt << 1)
        #define rs (rt << 1 | 1)
        #define mid ((l + r) >> 1)
        void Wpushup(int rt)
        {
            fo(i, 0, mod - 1) f[rt][i] = f[rs][f[ls][i]];
        }
        void Wbuild(int rt, int l, int r)
        {
            if(l == r)
            {
                fo(i, 0, mod - 1)
                {
                    if(d[l].fi == 1) f[rt][i] = (i + d[l].se) % mod;
                    else if(d[l].fi == 2) f[rt][i] = d[l].se * i % mod;
                    else f[rt][i] = Wqp(i, d[l].se);
                }
                return ;
            }
            Wbuild(ls, l, mid), Wbuild(rs, mid + 1, r);
            Wpushup(rt);
        }
        void Wupd(int rt, int l, int r, int x, int op, ll v)
        {
            if(l == r)
            {
                fo(i, 0, mod - 1)
                {
                    if(op == 1) f[rt][i] = (i + v) % mod;
                    else if(op == 2) f[rt][i] = v * i % mod;
                    else f[rt][i] = Wqp(i, v);
                }
                return ;
            }
            if(x <= mid) Wupd(ls, l, mid, x, op, v);
            else Wupd(rs, mid + 1, r, x, op, v);
            Wpushup(rt);
        }
    } t[5];
    void Wexgcd(int a, int b, int &x, int &y)
    {
        if(b == 0){x = 1, y = 0; return ;}
        Wexgcd(b, a % b, x, y);
        int z = x;
        x = y, y = z - (a / b) * y;
    }
    short main()
    {
        n = qr, m = qr, M = qr;
        fo(i, 2, 99)
        {
            if(!yz[i]) pri[++tot] = i;
            fo(j, 1, tot)
            {
                if(pri[j] * i > 99) break;
                yz[pri[j] * i] = 1;
                if(i % pri[j] == 0) break;
            }
        }
        int zc = M;
        fo(i, 1, tot)
        {
            bool yw = 0;
            while(zc % pri[i] == 0)
            {
                if(!yw) yw = 1, mod[++gs] = pri[i];
                else mod[gs] *= pri[i];
                zc /= pri[i];
            }
        }
        fo(i, 1, n)
        {
            string s; cin >> s;
            if(s[0] == '+') d[i].fi = 1;
            else if(s[0] == '*') d[i].fi = 2;
            else d[i].fi = 3;
            ll num = 0;
            fo(i, 1, s.size() - 1) num = num * 10 + s[i] - '0';
            d[i].se = num;
        }
        fo(i, 1, gs)
        {
            t[i].mod = mod[i];
            t[i].Wbuild(1, 1, n);
        }
        fo(i, 1, m)
        {
            int op = qr, x = qr;
            if(op == 1)
            {
                ll ans = 0;
                fo(j, 1, gs)
                {
                    int w = t[j].f[1][x % mod[j]];
                    int md1 = M / mod[j], inv, y;
                    Wexgcd(md1, mod[j], inv, y);
                    ans = (ans + 1ll * w * md1 % M * (inv + mod[j]) % M) % M;
                }
                printf("%lld\n", ans);
            }
            else
            {
                string s; cin >> s;
                ll zc = 0, num = 0;
                if(s[0] == '+') zc = 1;
                else if(s[0] == '*') zc = 2;
                else zc = 3;
                fo(j, 1, s.size() - 1) num = num * 10 + s[j] - '0';
                fo(j, 1, gs) t[j].Wupd(1, 1, n, x, zc, num);
            }
        }
        return Ratio;
    }
}
namespace Wisadel
{
    short main()
    {
        freopen("expr.in", "r", stdin) , freopen("expr.out", "w", stdout);
        int u = qr;
        if(u <= 3) return Wistask1::main();
        return Wvictoria::main();
        return Ratio;
    }
}
int main(){return Wisadel::main();}

别的先不说了,补眼睛鼻托去了。。。

标签:ch,04,int,zc,模拟,ans,mod,NOIP2024,fo
From: https://www.cnblogs.com/Ratio-Yinyue1007/p/18454824

相关文章

  • 人生模拟器免广告获取奖励 足够货币反加
    人生模拟器是一款可以让你体验不同生活方式的游戏,你可以选择成为学霸、股坛奇才,或是过上平淡生活的普通人。游戏中,你还可以投资餐饮公司、游戏公司,甚至参与竞选美国总统,探索和殖民火星。如果你正在寻找免广告获取奖励的方法,可以尝试下载人生模拟器免广告版,这样你就可以在没有......
  • 信息学奥赛复赛复习15-CSP-J2022-01乘方-数据类型、类型转换、数据类型溢出、指数、模
    PDF文档公众号回复关键字:202410091P8813[CSP-J2022]乘方[题目描述]小文同学刚刚接触了信息学竞赛,有一天她遇到了这样一个题:给定正整数a和b,求a^b的值是多少。a^b即b个a相乘的值,例如2^3即为3个2相乘,结果为2×2×2=8“简单!”小文心想,同时很快就写出了......
  • 10.9(NOIP 模拟赛 #10)
    2025--炼石计划--10月06日--NOIP模拟赛#10【订正】-比赛-梦熊联盟(mna.wang)复盘T1计数题,感觉不难。用样例模拟了一下,找到一个较优的去重方式。然后过了样例。此时8:10。T2好像又是矩阵加速。想正解。想不出来,只能做到\(\mathcalO(n^6\logk)\)的复杂度。......
  • 多校A层冲刺NOIP2024模拟赛04
    多校A层冲刺NOIP2024模拟赛04\(T1\)A.02表示法\(0pts/100pts\)弱化版:luoguP1010[NOIP1998普及组]幂次方递归模拟即可,二进制分解时需要写高精除低精。点击查看代码intr[810],t[810];chars[810],id[810][10];stringa;intchu(chars[]){ intn=strlen(s......
  • IEC104规约的秘密之七----配置参数t1,t2,t3
    104通讯前需要配置通讯参数,一般有如下参数:IP地址,端口号,k,w,t1,t2,t3,公共地址,遥控超时参数,104主规约还有一个t0参数。本次只讲解t1,t2,t3这两个参数。这三个都是超时时间,t1用于两个地方,一个是发送的I帧没有得到及时的确认,在规约文本中有如下图:B站发送I(0,0)帧后,开始计时,A站回......
  • fiddler抓模拟器的手机包
    1、fiddler中设置a、设置抓取https接口 b.设置端口和允许所有设备连接 下载  2、下载模拟器并打开模拟器 3、开始模拟器是平板模式,改成手机竖屏模式改成900*1600 4、在window中的运行中输入:inetcpl.cpl b、点击连接输入代理地址:127.0.0.1 端口号:8888 ......
  • HarmonyOS NEXT模拟登录页,华为账号一键登录
    一、介绍基于鸿蒙Next模拟账号一键登录,免去账号注册环节二、场景需求1. 用户场景新用户: 需要快速注册并登录,以体验华为的服务。老用户: 希望快速登录,不用每次输入用户名和密码。2. 界面设计Logo和标题: 页面顶部展示华为的Logo及"一键登录"或"华为账号登录"的标题。3.......
  • 【C++】priority_queue的介绍和模拟实现
    【C++】priority_queue的介绍和模拟实现一.priority_queue的介绍1.priority_queue的基本介绍2.priority_queue的使用介绍二.priority_queue的模拟实现一.priority_queue的介绍1.priority_queue的基本介绍优先队列是一种容器适配器,根据严格的弱排序标准,它的......
  • C++ day04(友元 friend、运算符重载、String字符串)
    目录【1】友元friend1》概念2》友元函数 3》友元类 4》友元成员函数 【2】运算符重载1》概念2》友元函数运算符重载 ​编辑 3》成员函数运算符重载4》赋值运算符与类型转换运算符重载 5》注意事项【3】String字符串类【1】友元friend1》概念定义:......
  • XYD1004CSPS
    T1序列[贪心,模拟]Description给定一个序列,每次可以将一个数减一,求让所有数字互不相同的最小操作数,\(0\)除外,也就是\(0\)可以相同。Solution贪心地,从大到小考虑每个数,都只需要减到第一个没有数出现的数。开个桶从大到小累计答案即可。T2XYD[构造]Description给定\(......