NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛24

前言

music
《春雪》

白是无尽的迷途

白是归零的法术

洗净 染渍 反复

练就成我温暖天赋 也不免再惹一身寒毒

冰是雪送的礼物

却不敌春来时的温度

融化 难以 碰触

沿着心底返流灌注 到面孔化作几滴泪珠

我想在冬夜雪地与你追逐

你却落在早春中的一棵树

一次错过不算错误

错在来不及看清楚

你的面目我就交出全部

雪花开在冬夜深处蔓延

蔓延到一个危险的春天

春天蚕食消融目空一切

一切啊那曾是我的世界

雪花开在冬夜深处蔓延

蔓延到一个危险的春天

我在原地守护我的体面

春天再见 春天再见

我还在冬夜雪地里等日出

你落满早春枝叶宣判我输

趁这错过还没结束

再请你跳一支舞

画下曼妙脚步作为庆祝

趁这错过还没结束

再送你一句祝福

落下枝叶时有人来接住

洛谷勾线出来了,我是压线大师,因为 T2 挂了所以是 \(160\) 分,\(6\) 级勾线是 \(165\),如果 \(T2\) 没挂就是 \(220\) 分,\(7\) 级勾线是 \(225\),去死吧 ̄へ ̄。

这是昨天的模拟赛,今天终于没有模拟赛了,O(∩_∩)O~~,赶紧补一补题,前天的还没改完(⊙o⊙)…

晚上一机房的人在那儿看国足赛况,field 进来 D 忘了谁在那儿大叫,然后说国足是 \(1:2\) 了吗你这么兴奋,然后我的电脑闪了一下,真成 \(1:2\) 了!?!见证国足 \(5\) 年来第一次进日本球。

好像好久模拟赛没上过 \(200\) 了,今天打得还行竟然 \(200+\)

image

T1 和 T3 是赛时切的,然后一下午加一晚上才把 T2 题解看懂,无语了,计数题是赛时推不出来但赛后能看懂题解,博弈论是连题解都看不懂,问题转化到最后感觉和题面都没啥关系。

赛时看到 T1 有模数直接不想看了(以为是计数),先去看 T3,发现是数据结构唉,有点思路但不多,再回去看 T1 发现 kmp 写脸上了,于是做掉 T1 回去看 T3;发现那个思路一点问题没有,于是打了 T3,T3 打到一半发现 T1 好像复杂度打错了成 \(O(n^2)\) 了(这样还有 \(95\)),但是错的不多,改一小下就成 \(O(n)\) 了;想打一打 T4 的 \(30\) 分,发现不会,就写了个 \(10\) 分;写 T2?我去博弈论真是我赛时能做的?爆搜一分没有?肯定是要观察一些性质的吧,去他丫的结论题,于是继续写 T4,最后 T2 写了个 puts("0") 上去了有 \(10\) 分。

T3 赛时犯唐求前缀第一个大于 \(a_i\) 的数用的 ST 表加二分,OJ 能过但是 accoders 上直接被卡常了,huge 把时限改成了 \(1.5s\) 就过了,赛后发现直接单调栈就行了,改了之后是最优解。

T1 选取字符串

border 这种东西直接把 kmp 写脸上了,求出来 \(next\) 数组,考虑可以建树,\(fa_i=next_i\),之后就可以树上,对于每个节点统计他的子树,但是发现满足 \(fa_i<i\),所以完全不用把树建出来,直接倒着递推一遍即可,因为是递推所以是最优解。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e6+10,P=998244353;
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,jc[N],inv[N],nxt[N],sum[N],cnt[N]; char s[N];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
inline int qpow(ll a,int b)
{ll res=1; for(;b;(a*=a)%=P,b>>=1) (b&1)&&((res*=a)%=P); return res;}
inline ll C(int n,int m) {return n<m?0:1ll*jc[n]*inv[n-m]%P*inv[m]%P;}
signed main()
{
	freopen("string.in","r",stdin),freopen("string.out","w",stdout);
	read(m),scanf("%s",s+1),n=strlen(s+1),jc[0]=jc[1]=1;
	for(int i=2,j=0;i<=n;i++)
	{
		while(j&&s[j+1]!=s[i]) j=nxt[j];
		nxt[i]=(j+=(s[j+1]==s[i])),jc[i]=1ll*jc[i-1]*i%P;
	}
	for(int i=1;i<=n;i++) cnt[i]=cnt[nxt[i]]+1;
	for(int i=0;i<=n;i++) cnt[i]<<=1,cnt[i]++;
	inv[n+1]=qpow(jc[n+1]=1ll*jc[n]*(n+1)%P,P-2),fill(sum,sum+1+n,1);
	for(int i=n;~i;i--) inv[i]=1ll*inv[i+1]*(i+1)%P;
	for(int i=n;~i;i--) ans=mod(ans,C(sum[i],m)*cnt[i]%P),sum[nxt[i]]+=sum[i];
	write(ans);
}

T2 取石子

发现若 \(\sum\limits_{i=1}^{n}a_i\) 为奇数,则 Alice 直接拿 \(1\) 就赢了,考虑如果是偶数怎么办。

发现两人此时一定只拿偶数,不然把奇数给对面对面就赢了,所以问题可以转换为 \(K\to \lfloor\dfrac{K}{2}\rfloor,a_i\to \lfloor\dfrac{a_i}{2}\rfloor\) 的形式,就这样不停地转化直到 \(\sum\limits_{i=1}^{n}a_i\) 为奇数时 Alice 就赢了。

所以若存在一个 \(t\le \log_2K\) 满足 \(\sum\limits_{i=1}^{n}\lfloor\dfrac{a_i}{2^t}\rfloor\) 为奇数时 Alice 必胜,可以转化为 \(\text{lowbit}(\oplus_{i=1}^{n}a_i)\le K\),这里钦定 \(\text{lowbit}(0)=\infty\)

接下来考虑 Alice 第一步怎么拿,设 \(sum=\oplus_{i=1}^{n}a_i\)Alice 第一步拿的是 \((i,x)\),那么一定是要让 \(\text{lowbit}(sum\oplus a_i\oplus (a_i-x))>x\),所以一定是拿 \(sum\) 在二进制中是 \(1\) 的位置,且若高位拿了低位一定要跟着拿,所以直接枚举 \(i\) 和二进制位即可,复杂度 \(O(n\log v)\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define lowbit(x) (x&-x)
using namespace std;
const int N=5e4+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char a=getchar_unlocked();
	for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=0;
	for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^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,sum,a[N];
inline bool check(int x,int y) {return x&&lowbit(x)<=y;}
signed main()
{
	freopen("nim.in","r",stdin),freopen("nim.out","w",stdout);
	read(n,m); for(int i=1;i<=n;i++) read(a[i]),sum^=a[i];
	if(!check(sum,m)) return puts("0"),0; puts("1");
	for(int i=1,p,vl;i<=n;i++)
	{
		p=0,vl=sum; for(int j=0;j<=30;j++) if((vl>>j)&1)
		{
			vl^=(a[i]-p),p|=1<<j; if(p>m||p>a[i]) break;
			vl^=(a[i]-p); if(!check(vl,p)) write(i,p),puts("");
		}
	}
}

T3 均衡区间

发现一个区间 \([l,r]\) 合法的充要条件是 \(\exists i,j,k,h\in (l,r),a_i>a_l\wedge a_j<a_l\wedge a_k>a_r\wedge a_h<a_r\)

那么对于一个 \(r\),找到它前面第一个 \(i\) 满足 \(a_i>a_r\) 和第一个 \(j\) 满足 \(a_j<a_r\),那么对于一个 \(l\) 能和 \(r\) 配对的必要条件是 \(l<\min(i,j)\)

同理对于一个 \(l\),找到它后面第一个 \(i\) 满足 \(a_i>a_l\) 和第一个 \(j\) 满足 \(a_j<a_l\),那么对于一个 \(r\) 能和 \(l\) 配对的必要条件是 \(r>\max(i,j)\)

那么对于区间 \([l,r]\) 合法的充要条件就是 \(l<\min(i_r,j_r)\wedge r>\max(i_l,j_l)\),发现原问题转换为了一个二位数点问题。

单调栈求出对应条件,排完序后直接扫描线即可,复杂度 \(O(n\log n)\)

  • 数据范围是 \(10^6\) 且只开了 \(1s\) 应该想到什么:排除树状数组以外的所有数据结构。
点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define lowbit(x) (x&-x)
using namespace std;
const int N=1e6+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char a=getchar_unlocked();
	for(;!isdigit(a);a=getchar_unlocked()) if(a=='-') z=0;
	for(;isdigit(a);a=getchar_unlocked()) x=(x<<1)+(x<<3)+(a^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,_,a[N],ansl[N],ansr[N],sta1[N],sta2[N]; struct aa {int x,id;}pre[N],suf[N];
inline void add1(int x) {for(;x;x-=lowbit(x)) a[x]++;}
inline int ask1(int x) {int res=0; for(;x<=n;x+=lowbit(x)) res+=a[x]; return res;}
inline void add2(int x) {for(;x<=n;x+=lowbit(x)) a[x]++;}
inline int ask2(int x) {int res=0; for(;x;x-=lowbit(x)) res+=a[x]; return res;}
signed main()
{
	freopen("interval.in","r",stdin),freopen("interval.out","w",stdout);
	read(n,_); for(int i=1;i<=n;i++) read(a[i]);
	sta1[0]=sta2[0]=1; for(int i=1,top1=0,top2=0;i<=n;i++)
	{
		while(top1&&a[i]>=a[sta1[top1]]) top1--;
		while(top2&&a[i]<=a[sta2[top2]]) top2--;
		pre[i]={min(sta1[top1],sta2[top2]),sta1[++top1]=sta2[++top2]=i};
	}
	sta1[0]=sta2[0]=n; for(int i=n,top1=0,top2=0;i;i--)
	{
		while(top1&&a[i]>=a[sta1[top1]]) top1--;
		while(top2&&a[i]<=a[sta2[top2]]) top2--;
		suf[i]={max(sta1[top1],sta2[top2]),sta1[++top1]=sta2[++top2]=i};
	}
	memset(a,0,4*(n+1)),sort(suf+1,suf+1+n,[](aa a,aa b){return a.x>b.x;});
	sort(pre+1,pre+1+n,[](aa a,aa b){return a.id>b.id;});
	for(int i=1,j=1;i<=n;ansl[suf[i].id]=ask1(suf[i].id),i++)
		while(j<=n&&pre[j].id>suf[i].x) add1(pre[j++].x-1);
	memset(a,0,4*(n+1)),sort(pre+1,pre+1+n,[](aa a,aa b){return a.x<b.x;});
	sort(suf+1,suf+1+n,[](aa a,aa b){return a.id<b.id;});
	for(int i=1,j=1;i<=n;ansr[pre[i].id]=ask2(pre[i].id),i++)
		while(j<=n&&suf[j].id<pre[i].x) add2(suf[j++].x+1);
	for(int i=1;i<=n;i++) write(ansl[i]),putchar_unlocked(' '); puts("");
	for(int i=1;i<=n;i++) write(ansr[i]),putchar_unlocked(' '); puts("");
}

T4 禁止套娃

我甚至都没有改到这道题,好像几乎也没人改,那就不改了,感觉可以写一下 \(30\) 的部分分。

posted @ 2024-11-20 08:44  卡布叻_周深  阅读(18)  评论(0编辑  收藏  举报