NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛25
前言
music
《浮游》
天已经微亮 我睁开双眼
长夜漫漫总有散 来到故事终点
如果有人问 此生不悔
碰触着你的地方 刻下纠缠印痕
说再见不是离别 何必追赶着句点
思念在一瞬间
倾倒地平线
荒野在歌唱
大地在缄默
光粒穿透海
尘埃中花开
游蜉望着天
誓言追光影
灵魂在寻找 时间缝隙
和你的方向
寻寻觅觅也不曾怀疑
思念描绘你轮廓
命运是否能重叠
说永远太过遥远
让瞬间冻结时间
浮游在天地间
拥抱着原点
荒野在歌唱
大地在缄默
光粒穿透海
尘埃中花开
游蜉望着天
誓言追光影
灵魂在寻找 时间缝隙
和你的方向
传奇太遥远
良夜已来临
我们的歌谣
回响在远方
四季的轮换
渺小也伟大
最后的箴言 流唱世间
是心永不灭
我恼了连着打了多少天模拟赛了,根本改不完,已经忘了这场是哪天打的了。
T1 直接 bitset 操过去了,T2 想 DP,发现复杂度是假的还需要高精度,给我糖丸了的那儿打高精度,打着打着开始想骂出题人然后反应过来是不是根本不用高精度直接贪心就行了,原来小丑是我自己,直接全变成乘法就行了,然后没有打完,赛后看题解和我的做法一模一样,恼了。
T2 最后写不完了摆了,直接把做法写在注释里了,就当我过了……
T2 有不少细节,出题人精心挖的坑全让造数据的填了,先是炸 long long,不过开 __int128 就行了,再是 \(x\equiv 0\) 的需要特判,然后加了两组 hack,然后赛时就只剩一个最劣解过了……
T1 图
直接 bitset 就行了。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e4+10;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar_unlocked();
for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,ans; char s[N]; bitset<N>vis,e[N];
signed main()
{
freopen("a.in","r",stdin),freopen("a.out","w",stdout);
read(n,m);
for(int i=1;i<=m;i++)
{
scanf("%s",s+1);
for(int j=1;j<=n;j++) vis[j]=(s[j]=='1'||s[j]=='3');
for(int j=1;j<=n;j++) if(s[j]=='2'||s[j]=='3') e[j]^=vis;
for(int j=1;j<=n;j++) vis[j]=(s[j]=='2'||s[j]=='3');
for(int j=1;j<=n;j++) if(s[j]=='1'||s[j]=='3') e[j]^=vis;
for(int j=1;j<=n;j++) vis[j]=(s[j]=='3');
for(int j=1;j<=n;j++) if(s[j]=='3') e[j]^=vis;
for(int j=1;j<=n;j++) e[j][j]=0;
}
for(int i=1;i<=n;i++) ans+=e[i].count(); write(ans>>1);
}
T2 序列
对于每个点 操作 \(1\) 只会进行一次,操作 \(2\) 一定先进行贡献大的。
所以可以将操作 \(1\) 看做操作 \(2\),贡献为 \(y-x\),之后按大小排序,第 \(i\) 个操作的贡献就可以转化为 \(\times \dfrac{x+\sum\limits_{j=1}^{i}y_j}{x+\sum\limits_{j=1}^{i-1}y_j}\)。
由此全部转化为了乘法,排一遍序往里加即可。
一些细节:
- 贡献 \(<1\) 的不要进行,因为是不超过 \(k\) 不是恰好为 \(k\)。
- 排序用分数有炸 long long 的风险,用 double 有炸精度的风险,分别注意。
- 对于 \(x\equiv 0\) 的情况,若 \(\dfrac{x}{y}\) 满足 \(y=0\),说明其前一定有 \(\dfrac{x'}{y'}\) 满足 \(x'=0\),记录一下 \(\equiv 0\) 的个数即可。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e5+10,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar_unlocked();
for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,tot,b[N]; ll a[N],ans=1; vector<int>e[N]; struct aa {ll x,y;}q[N];
inline ll qpow(ll a,int b)
{ll res=1; for(a%=P;b;(a*=a)%=P,b>>=1) (b&1)&&((res*=a)%=P); return res;}
signed main()
{
freopen("b.in","r",stdin),freopen("b.out","w",stdout);
read(n,m); for(int i=1;i<=n;i++) read(a[i]),(ans*=(b[i]=a[i]))%=P;
for(int i=1,op,x,y;i<=m;i++)
{
read(op,x,y); if(op==1) b[x]=max(b[x],y);
else if(op==2) e[x].push_back(y); else q[++tot]={1,y};
}
for(int i=1;i<=n;i++)
{
if(b[i]!=a[i]) e[i].push_back(b[i]-a[i]);
sort(e[i].begin(),e[i].end(),greater<int>());
for(int j:e[i]) q[++tot]={a[i],a[i]+j},a[i]+=j;
}
sort(q+1,q+1+tot,[](aa a,aa b){return (__int128)a.y*b.x>(__int128)b.y*a.x;});
for(int i=0,j=1,x,y,cnt=0;i<=m;i++,j++)
{
write((!cnt)*ans),putchar_unlocked(' '); if(j<=tot)
{
if(!(q[j].y%P)) q[j].y/=P,cnt++;
if(!(q[j].x%P)) q[j].x/=P,cnt--;
(ans*=q[j].y*qpow(q[j].x,P-2)%P)%=P;
}
}
}
T3 树
不会。
T4 字符串
难点在于询问,发现是 \(\{(i,i+1)\mid rk_i>rk_{i+1}\}\) 的元素数量,\(rk\) 是按 \(t\) 的顺序排的,于是可以用线段树维护。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mid (l+r>>1)
#define ls (mid<<1)
#define rs (mid<<1|1)
#define calc(x) (((x)>=k?(x)-k:(x)))
using namespace std;
const int N=2e5+10,P=1e9+7;
template<typename Tp> inline void read(Tp&x)
{
x=0;register bool z=true;
register char c=getchar_unlocked();
for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,k,id[N]; char s[N];
struct aa
{
int pre,suf,add,sum[10][10]; aa(){add=0;}
inline aa operator + (const aa &a) const
{
aa tmp; for(int i=0;i<k;i++) for(int j=0;j<k;j++)
tmp.sum[i][j]=sum[i][j]+a.sum[i][j];
return tmp.sum[suf][a.pre]++,tmp.pre=pre,tmp.suf=a.suf,tmp;
}
inline aa operator + (const int &d) const
{
aa tmp; tmp.pre=calc(pre+d),tmp.suf=calc(suf+d);
for(int i=0;i<k;i++) for(int j=0;j<k;j++)
tmp.sum[calc(i+d)][calc(j+d)]=sum[i][j];
return tmp.add=calc(add+d),tmp;
}
}t[N<<1];
inline void build(int p,int l,int r)
{
if(l==r) return t[p].pre=t[p].suf=s[l]-'a',void();
build(ls,l,mid),build(rs,mid+1,r),t[p]=t[ls]+t[rs];
}
inline void change(int p,int l,int r,int vl,int vr,int d)
{
if(vl<=l&&vr>=r) return t[p]=t[p]+d,void();
if(t[p].add) t[ls]=t[ls]+t[p].add,t[rs]=t[rs]+t[p].add,t[p].add=0;
if(vl<=mid) change(ls,l,mid,vl,vr,d);
if(vr>mid) change(rs,mid+1,r,vl,vr,d); t[p]=t[ls]+t[rs];
}
inline aa ask(int p,int l,int r,int vl,int vr)
{
if(vl<=l&&vr>=r) return t[p];
if(t[p].add) t[ls]=t[ls]+t[p].add,t[rs]=t[rs]+t[p].add,t[p].add=0;
if(vr<=mid) return ask(ls,l,mid,vl,vr);
if(vl>mid) return ask(rs,mid+1,r,vl,vr);
return ask(ls,l,mid,vl,vr)+ask(rs,mid+1,r,vl,vr);
}
inline int ask(int l,int r,int res=1)
{
aa tmp=ask(1,1,n,l,r); for(int i=1;i<=k;i++) id[s[i]-'a']=i;
for(int i=0;i<k;i++) for(int j=0;j<k;j++)
res+=(id[i]>=id[j])*tmp.sum[i][j]; return res;
}
signed main()
{
freopen("d.in","r",stdin),freopen("d.out","w",stdout);
read(n,m,k),scanf("%s",s+1),build(1,1,n);
for(int op,l,r,x;m;m--)
{
read(op,l,r); if(op==1) read(x),change(1,1,n,l,r,x);
else scanf("%s",s+1),write(ask(l,r)),puts("");
}
}