NOIP2024 前集训:NOIP2024加赛 2

前言

T2 开太晚了,没打完,别的没怎么挂。

哦对,T1 以为埃筛复杂度是 \(n log^2\),实际上是 \(n \ln(\ln (n))\),结果以为复杂度是错的,然后本地不开 O2 都飞快,我甚至还在惊叹本地竟然能跑 \(5e9\)……

还有我之前不知道树的直径的中点时唯一的……

T1 新的阶乘

直接埃筛做完了。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=1e7+10,M=7e6+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,tot,prime[M]; ll cnt[M]; bool vis[N];
inline int calc(int x,int y,int res=0) {while(!(x%y)) x/=y,res++; return res;}
signed main()
{
	freopen("factorial.in","r",stdin),freopen("factorial.out","w",stdout);
	read(n),prime[++tot]=2;
	for(int i=2;i<=n;i+=2) vis[i]=1,cnt[1]+=calc(i,2)*(n-i+1);
	for(int i=3;i<=n;i+=2) if(!vis[i])
	{
		prime[++tot]=i;
		for(int j=i;j<=n;j+=i) vis[j]=1,cnt[tot]+=calc(j,i)*(n-j+1);
	}
	printf("f(%d)=",n);
	for(int i=1;i<tot;i++)
	{
		write(prime[i]);
		if(cnt[i]^1) putchar_unlocked('^'),write(cnt[i]);
		putchar_unlocked('*');
	}
	write(prime[tot]); if(cnt[tot]^1) putchar_unlocked('^'),write(cnt[tot]);
}

T2 博弈树

发现 Bob 只有在起点为直径的中点时必胜,其他 Alice 必胜。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define pb push_back
using namespace std;
const int N=1e5+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,s,t,mx,lca,mid,f[N],g[N],fa[N],pos1[N],pos2[N]; vector<int>e[N];
inline void dfs(int x,int dad)
{
	fa[pos1[x]=pos2[x]=x]=dad; for(int y:e[x]) if(y!=dad)
	{
		dfs(y,x); if(f[x]<f[y]+1)
			pos2[x]=pos1[x],pos1[x]=pos1[y],g[x]=f[x],f[x]=f[y]+1;
		else if(g[x]<f[y]+1) pos2[x]=pos1[y],g[x]=f[y]+1;
	}
	if(f[x]+g[x]>=mx) s=pos1[x],t=pos2[x],lca=x,mx=f[x]+g[x];
}
signed main()
{
	freopen("tree.in","r",stdin),freopen("tree.out","w",stdout);
	read(n,m); for(int i=1,x,y;i<n;i++) read(x,y),e[x].pb(y),e[y].pb(x);
	dfs(1,0); if(mx&1) {while(m--) puts("Alice"); return 0;}
	for(int i=s,sum=0;i!=lca&&!mid;i=fa[i],sum++) if(sum==(mx>>1)) mid=i;
	for(int i=t,sum=0;i!=lca&&!mid;i=fa[i],sum++) if(sum==(mx>>1)) mid=i;
	if(!mid) mid=lca; for(int x;m;m--) read(x),puts(x!=mid?"Alice":"Bob");
}

T3 划分

数据点分治,当前缀 \(0\) 个数 \(\ge m-1\) 时第一问就是后面的全取就行了,第二问就是在前缀 \(0\) 里插板。

否则发现答案一定选择一个长度为 \(n-m+1\) 的区间,其他的区间都长度为 \(1\),因为这是 C++,所以需要用二分哈希找到 \(lcp\) 然后比较第 \(lcp+1\) 位判大小,然后就能找到最优区间了,但是第二问发现只要满足前 \(n-m\) 位相同即可,因为后面的 \(1\) 会补上。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e6+10,B=233,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,vl,vr,nl,nr,ans,lcp,sum,b[N],h[N],jc[N],inv[N]; char s[N];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
inline int ask(int l,int r) {return mod(h[r],P-1ll*h[l-1]*b[r-l+1]%P);}
inline bool check(int x,int y,int mid) {return ask(x,x+mid-1)==ask(y,y+mid-1);}
inline int calc(int l,int r,ll v=1,int res=0,int sum=0)
{
	for(int i=r;i>=l;i--,(v<<=1)%=P) res=mod(res,(s[i])*v),sum+=s[i];
	return res+(::sum-sum);
}
inline ll qpow(ll a,int b,ll res=1)
{for(;b;(a*=a)%=P,b>>=1) (b&1)&&((res*=a)%=P); return res;}
inline int C(int n,int m) {return 1ll*jc[n]*inv[n-m]%P*inv[m]%P;}
inline int num(int sum=m-1,int res=0,ll c=1)
{
	for(int i=m;i<=n;i++) if(!s[i]) sum++; else break; sum-=(sum==n);
	jc[0]=1; for(int i=1;i<=n;i++) jc[i]=1ll*jc[i-1]*i%P;
	inv[n]=qpow(jc[n],P-2); for(int i=n-1;~i;i--) inv[i]=1ll*inv[i+1]*(i+1)%P;
	for(int i=m-1;i<=sum;i++) res=mod(res,C(sum,i));
	return res;
}
signed main()
{
	freopen("divide.in","r",stdin),freopen("divide.out","w",stdout);
	read(n,m),scanf("%s",s+1); for(int i=1;i<=n;i++) s[i]-='0';
	for(int i=1;i<=n;i++) sum+=s[i]; if(n==m) return write(sum,1),0;
	for(int i=1;i<m;i++) if(s[i]) {ans=1,m=n-m+1; break;}
	if(!ans) return write(calc(m,n),num()),0;
	b[0]=1; for(int i=1;i<=n;i++) b[i]=1ll*b[i-1]*B%P;
	for(int i=1;i<=n;i++) h[i]=1ll*h[i-1]*B%P+s[i];
	for(vl=1,vr=m,nl=2,nr=m+1;nr<=n;nl++,nr++)
	{
		for(int l=0,r=m-1,mid;l<=r;)
			check(nl,vl,mid=l+r>>1)?(l=mid+1)&&(lcp=mid):(r=mid-1);
		lcp==m-1?(ans++):(s[nl+lcp])&&(vl=nl)&&(vr=nr)&&(ans=1);
	}
	write(calc(vl,vr),ans);
}

T4 灯笼

有这题吗?

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