『模拟赛』暑假集训CSP提高模拟27 || The End

《$Never\;Over$》

好久没推歌了。

I don't know what to say
I don't know what to do
I just wanna go right back to you
Like a cloud in the sky
My tears fall for you
I would paint my life
White just to make you blue
Cause baby you know we should be together
Cause lately I've been thinking about you
It's hard to cover
Baby you know you could pull me closer
Cuz we know in our hearts we're never over
Never over
Cuz we know in our hearts we're never over
Baby you know you could pull me closer
Cuz we know in our hearts we're never over
Every single touch
Every single moan
Your love got me intoxicated nice and slow
Every time we used to not know where to go
But baby anywhere is home with you
Cuz baby you know we should be together
Cuz lately I've been thinking about you
It's hard to cover
Baby you know you could pull me closer
Cuz we know in our hearts we're never over
Never over
Cuz we know in our hearts we're never over
Cuz baby you know we should be together
Cuz lately I've been thinking about you
It's hard to cover
Baby you know you could pull me closer
Cuz we know in our hearts we're never over

Upd:更新了 T2 推柿子部分

写后面怕没人看

我改了整整三回啊,三回,每回都得重新打理这坨使

image


Rank

暑假集训,谢幕!

image

A. 线性只因

暗藏玄只因

签。

考虑到按位与运算二者均为 1 为 1,因此我们倒序枚举二进制下位数,若当前合法的数中该位为 1 的数量大于 \(m\) 则计入答案,并将不为 1 的数标记为不合法。由于在二进制下,最高位位数高的数一定大,因此这样选数是有正确性的。值域范围 \(\le 10^9\),我们只需从 \(30\) 往下枚举,时间复杂度 \(\mathcal{O(31n)}\)

点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
inline int qr()
{
	char ch=getchar();int 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;
}
#define qr qr()
const int Ratio=0;
const int N=1e6+5;
int n,m,ans;
int a[N];
bool yz[N];
namespace Wisadel
{
    short main()
    {
        n=qr,m=qr;
        fo(i,1,n) a[i]=qr;
        fu(j,30,0)
        {
            int zc=0;
            fo(i,1,n) if((a[i]>>j)&1&&!yz[i]) zc++;
            if(zc>=m)
            {
                ans+=(1<<j);
                fo(i,1,n)
                    if(!((a[i]>>j)&1)) yz[i]=1;
            }
        }
        printf("%lld\n",ans);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

B. 金箱子

看到期望 dp 就似了。

赛时先被取模概率硬控,然后又因为没细看题被硬控,最后只拿到 \(\mathcal{O(2^n)}\) 暴力和 \(k=1\) 的30pts。

考虑正解,发现最终结果含和的幂形式,因此不能按一般情况下直接分开计算。仔细研究发现,导致我们不能简单算的罪魁祸首是指数 \(k\),所以想办法将它化掉或者转移。

\(f_{i,j}\) 表示到第 \(i\) 个鱼饵纳税的指数为 \(j\) 的情况下纳税的期望值,那么最终答案很显然为 \(f_{n,k}=\left(\operatorname{n 个点的单点贡献}\right)^k\)。有点复杂,先考虑 \(k=1\) 的情况,令 \(w_i=p_i\cdot a_i+\left(1-p_i\right)\cdot b_i\),则有 \(f_{n,1}=\sum_{i=1}^n w_i\),那么自然得到转移方程 \(f_{i,1}=f_{i-1,1}+w_i\)

现在将其扩展到 \(k\neq 1\) 的情况,设当前更新到点 \(i\),则前面共有 \(2^{i-1}\) 种情况,设每种情况中价值为 \(V_x\),发生的概率为 \(P_{x}\),则可以写出的式子为:

\[f_{i,k}=\sum_x p_i\cdot\left(V_x+a_i\right)^k\cdot P_x +\left(1-p_i\right)\cdot \left(V_x+b_i\right)^k\cdot P_x \]

看到幂,考虑使用二项式定理处理,于是有:

\[\begin{aligned} f_{i,k} &= \sum_x p_i\cdot\left(V_x+a_i\right)^k\cdot P_x +\left(1-p_i\right)\cdot \left(V_x+b_i\right)^k\cdot P_x\\&=\sum_x p_i\cdot \sum_{j=0}^k \binom{k}{j}\left(V_x\right)^j\cdot \left(a_i\right)^{k-j}\cdot P_x+\left(1-p_i\right)\cdot \sum_{j=0}^k \binom{k}{j}\left(V_x\right)^j\cdot \left(b_i\right)^{k-j}\cdot P_x \\ &= \sum_x\sum_{j=0}^k \binom{k}{j}\left(V_x\right)^j\cdot P_x\cdot\left(p_i\cdot\left(a_i\right)^{k-j}+\left(1-p_i\right)\cdot\left(b_i\right)^{k-j} \right) \end{aligned} \]

重新令 \(w_{i,j}=p_i\cdot \left(a_i\right)^j+\left(1-p_i\right)\cdot\left(b_i\right)^j\),继续化简:

\[\begin{aligned} f_{i,k} &= \sum_x \sum_{j=0}^k \binom{k}{j} \left(V_x\right)^j\cdot w_{i,k-j}\cdot P_x\\ &=\sum_{j=0}^k \sum_x \binom{k}{j} \left(V_x\right)^j\cdot w_{i,k-j}\cdot P_x \\ &= \sum_{j=0}^k \binom{k}{j}w_{i,k-j} \sum_x \left(V_x\right)^j\cdot P_x \end{aligned} \]

发现最后一项 \(\sum_x \left(V_x\right)^j\cdot P_x\) 就是我们所求的 \(f_{i-1,j}\),那么最终状态转移方程就出来了:

\[f_{i,k}=\sum_{j=0}^k \binom{k}{j}\left(w_i\right)^{k-j} \cdot f_{i-1,j} \]

这里面组合数和 \(w_i\) 的不同指数的幂值都是我们可以 \(\mathcal{O(n k)}\) 预处理出来的,那么我们就可以愉快的进行 dp 了!需要枚举 \(i\) 以及两层指数 \(j\)\(k\),时间复杂度为 \(\mathcal{O(nk^2)}\).

点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
typedef long long ll;
inline int qr()
{
	char ch=getchar();int 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;
}
#define qr qr()
const int Ratio=0;
const int N=1e4+5,M=105;
const int mod=998244353;
int n,m,p[N],a[N],b[N];
ll ans,C[M][M],w[N][M],f[N][M];
namespace Wisadel
{
    inline 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;
    }
    short main()
    {
        n=qr,m=qr;
        fo(i,1,n) p[i]=qr,a[i]=qr%mod,b[i]=qr%mod;
        fo(i,0,m)
        {
            C[i][0]=1;
            fo(j,1,i) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
        }
        fo(i,1,n) fo(j,0,m)
            w[i][j]=(p[i]*Wqp(a[i],j)%mod+(1-p[i]+mod)%mod*Wqp(b[i],j)%mod)%mod;
        f[0][0]=1;
        fo(i,1,n) fo(j,0,m) fo(k,0,j)
            f[i][j]=(f[i][j]+C[j][k]*f[i-1][k]%mod*w[i][j-k]%mod)%mod;
        printf("%lld\n",f[n][m]);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

C. 可持久化字符串

板子题?

赛时想到过 AC 自动机但因为学得不熟所以没敢写,只写了暴力 \(\mathcal{O(mq)}\) 的 kmp 做法结果还挂了只拿了 10pts。

正解就是 AC 自动机板子,借鉴的 wang54321 的做法,对于每个操作一,直接在 Trie 树中插入节点即可,操作二删除即可,操作三记录。然后跑出 fail 数组,由 fail 向当前节点连边,之后跑一遍 dfs,更新每个节点的贡献,最后用前缀和统计每个版本的答案输出即可。

点击查看代码
#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 fi first
#define se second
const int Ratio=0;
const int N=2e5+5;
const int mod=998244353;
int n,m,zc;
int L[N],R[N],rot[N],fx[N],fail[N],sum[N],num[N],cnt,cntq,tot;
int hh[N],ne[N],tr[N][27];
string B;
char ch;
namespace Wisadel
{
    int Wins(int now,char ch)
    {
        if(!tr[now][ch-'a']) tr[now][ch-'a']=++tot,fx[tot]=now;
        return tr[now][ch-'a'];
    }
    int Wdel(int now)
    {
        return fx[now];
    }
    void Wbuild()
    {
        queue<int>q;
        fo(i,0,25) if(tr[0][i]) q.push(tr[0][i]);
        while(q.size())
        {
            int now=q.front();q.pop();
            fo(i,0,25)
                if(tr[now][i]) fail[tr[now][i]]=tr[fail[now]][i],q.push(tr[now][i]);
                else tr[now][i]=tr[fail[now]][i];
        }
    }
    void Wadd(int u,int v)
    {
        ne[v]=hh[u];hh[u]=v;
    }
    void Wdfs(int u)
    {
        for(int i=hh[u];i;i=ne[i])
            Wdfs(i),num[u]+=num[i];
    }
    void Wsol(int now)
    {
        fo(i,1,tot) Wadd(fail[i],i);
        if(!now) return;
        while(now) num[now]++,now=fx[now];
        Wdfs(now);
    }
    short main()
    {
        // freopen("c.in","r",stdin),freopen(".out","w",stdout);
        n=qr,m=qr;sum[0]=1;
        cin>>B;B=" "+B;
        fo(i,1,n)
        {
            int op=qr,a,l,r;
            if(op==1)
                a=qr,cin>>ch,rot[++cnt]=Wins(rot[a],ch);
            else if(op==2)
                a=qr,rot[++cnt]=Wdel(rot[a]);
            else
                l=qr,r=qr,L[++cntq]=l,R[cntq]=r;
        }
        zc=0;
        fo(i,1,m) zc=Wins(zc,B[i]);
        Wbuild();Wsol(zc);
        fo(i,1,cnt)
            if(rot[i]) sum[i]=num[rot[i]];
            else sum[i]=1;
        fo(i,1,cnt) sum[i]+=sum[i-1];
        fo(i,1,cntq)
            if(!L[i]) printf("%d\n",sum[R[i]]);
            else printf("%d\n",sum[R[i]]-sum[L[i]-1]);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

D. 圣诞树

chino 可爱捏

好像 T4 就从来没挣扎过想正解。

赛时唐乐,打了个常数极大的暴力,只有 20pts。

70pts 做法正解是利用树剖求 lca,然后暴力跳父亲即可。倍增 lca 常数大,只能拿 50pts。

70pts 代码
#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 fi first
#define se second
const int Ratio=0;
const int N=5e5+5;
const int mod=998244353;
int n,m,st,ed;
int a[N],ans;
int hh[N],to[N<<1],ne[N<<1],cnt,fx[N],dep[N],siz[N],top[N],son[N];
bool yz[N],ok;
namespace Wisadel
{
    void Wadd(int u,int v)
    {
        to[++cnt]=v;
        ne[cnt]=hh[u];
        hh[u]=cnt;
    }
    void Wdfs(int u,int fa)
    {
        fx[u]=fa;dep[u]=dep[fa]+1;siz[u]=1;
        for(int i=hh[u];i!=-1;i=ne[i])
        {
            int v=to[i];
            if(v==fa) continue;
            Wdfs(v,u);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]]) son[u]=v;
        }
    }
    void Wdfs1(int u,int tp)
    {
        top[u]=tp;
        if(!son[u]) return;
        Wdfs1(son[u],tp);
        for(int i=hh[u];i!=-1;i=ne[i])
        {
            int v=to[i];
            if(v==fx[u]||v==son[u]) continue;
            Wdfs1(v,v);
        }
    }
    int Wlca(int u,int v)
    {
        while(top[u]!=top[v])
        {
            if(dep[top[u]]<dep[top[v]]) swap(u,v);
            u=fx[top[u]];
        }
        if(u==v) return u;
        if(dep[u]<dep[v]) swap(u,v);
        return v;
    }
    short main()
    {
        n=qr,m=qr;
        memset(hh,-1,sizeof hh);
        int all=0;
        fo(i,1,n) a[i]=qr,all=max(all,a[i]);
        fo(i,1,n-1)
        {
            int u=qr,v=qr;
            Wadd(u,v),Wadd(v,u);
        }
        Wdfs(1,0);Wdfs1(1,1);
        while(m--)
        {
            st=qr,ed=qr;
            int lca=Wlca(st,ed);yz[a[lca]]=1;
            while(st!=lca) yz[a[st]]=1,st=fx[st];
            while(ed!=lca) yz[a[ed]]=1,ed=fx[ed];
            fo(i,1,all+1) if(!yz[i]){printf("%d\n",i);break;}
            fill(yz+1,yz+1+all,0);
        }
        return Ratio;
    }
}
int main(){return Wisadel::main();}

正解所需知识不足,遂咕咕咕。

烈阳渐敛,荫叶趋黄,看似漫长的暑假转瞬即逝,我们也站在了高二的起跑线上。

一整个暑假沉浸式 OI 锻炼,进步是飞速的,虽然过程中会有一些不和谐的小插曲,但结果总还是较圆满的。

再推一首
  • \(Die\;For\;You\)

Time slows down when it can get no worse
I can feel it running out on me
I don't want these to be my last words
All forgotten 'cause that's all they'll be
Now there's only one thing I can do
Fight until the end like I promised to
Wishing there was something left to lose
This could be the day I die for you
What do you see before it's over
Blinding flashes getting closer
Wish that I had something left to lose
This could be the day I die for you
This could be the day I die for you
This could be the day I die for you
This could be the day
Everything I know
Everything I hold tight
When to let it go
When to make em all fight
When I'm in control
When I'm out of my mind
When I gotta live
When I gotta die gotta die
Everything I know
Everything I hold tight
When to let it go
When to make em all fight
When I'm in control
When I'm out of my mind
When I gotta live
When I gotta die
This could be the day I die for you
Everything I know
Everything I hold tight
When to let it go
When to make em all fight
When I'm in control
When I'm out of my mind
When I gotta live
When I gotta die
Feeling like there's nothing I can do
This could be the end it's mine to choose
It's taken me my lifetime just to prove
This could be the day I die for you
Don't let it be the day
What do you see before it's over
Blinding flashes getting closer
Sacrificing everything I knew
This could be the day I die for you
This could be the day I die for you
Everything I know
Everything I hold tight
When to let it go
When to make em all fight
When I'm in control
When I'm out of my mind
When I gotta live
When I gotta die

无论如何,专注当下,每次机会当作破釜沉舟,就如我很喜欢的一句歌词:

\[\mathcal{Now\ there's\ only\ one\ thing\ I\ can\ do} \]

\[\mathcal{Fight\ until\ the\ end\ like\ I\ promised\ to} \]

虽然闭幕战打的不是很好,但只要坚持,总还有机会的,不是吗?

\[\Large{\mathcal{Summer\;vacation\;closing}} \]


完结撒花~

这回是真完结了(不过七天长假我来啦

posted @ 2024-08-22 21:03  DrRatio  阅读(80)  评论(0编辑  收藏  举报