【比赛记录】2025CSP+NOIP 冲刺模拟赛合集Ⅳ

HZOJ NOIP2025模拟3

A B C D Sum Rank
100 40 20 12 172 7/28

A. 变形怪

直接记忆化搜索即可。\(x\) 中包含前十个质数时答案最大,为 \(458123\),可以接受。

Code
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
int m;
ll n,a[17];
__gnu_pbds::cc_hash_table<ll,__gnu_pbds::null_type> ans;
il void dfs(ll x){
//	cout<<x<<'\n';
	if(ans.find(x)!=ans.end()){
		return ;
	}
	ans.insert(x);
	if(!x){
		return ;
	}
	for(int i=1;i<=m;i++){
		dfs(x/a[i]);
	}
}
int main(){
	freopen("set.in","r",stdin);
	freopen("set.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		cin>>a[i];
	}
	sort(a+1,a+m+1);
	m=unique(a+1,a+m+1)-a-1;
	dfs(n);
	cout<<ans.size();
	return 0;
}
}
int main(){return asbt::main();}
/*
562949953421312 10
2 3 5 7 11 13 17 19 23 29
*/

B. 忍者小队

\(b_x=\sum_{i=1}^{n}[x|S_i]\),可以调和级数求。于是有如果最小值存在则最大值为 \(b_x\),否则最大值也不存在。

记值域为 \(V\)。注意到前七个质数的乘积就超过了 \(V\),所以 \(k=1\) 时答案最多为 \({7\choose6}=7\),显然 \(k\) 更大时答案也不会超过 \(7\)。考虑枚举每个答案是否可行。假设当前枚举到了 \(t\),设 \(f_x\) 表示选出 \(t\) 个数使它们的 \(\gcd=x\) 的方案数,则有:

\[f_x={b_x\choose t}-\sum_{i=2}^{\lfloor\frac{V}{x}\rfloor}f_{ix} \]

于是若 \(f_x=0\)\(t\) 不可行,否则可行。时间复杂度 \(O(7V\ln V)\)

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=3e5+5,mod=1e9+7,V=3e5,inf=1e9;
il int pls(int x,int y){
	return x+y<mod?x+y:x+y-mod;
}
il void add(int &x,int y){
	x=pls(x,y);
}
il int mns(int x,int y){
	return x<y?x-y+mod:x-y;
}
il void sub(int &x,int y){
	x=mns(x,y);
}
int n,m,a[maxn],fac[maxn],inv[maxn],tong[maxn],f[maxn],g[maxn],ans[maxn];
il int qpow(int x,int y=mod-2){
	int res=1;
	while(y){
		if(y&1){
			res=res*1ll*x%mod;
		}
		x=x*1ll*x%mod,y>>=1;
	}
	return res;
}
il void init(int n=V){
	fac[0]=1;
	for(int i=1;i<=n;i++){
		fac[i]=fac[i-1]*1ll*i%mod;
	}
	inv[n]=qpow(fac[n]);
	for(int i=n;i;i--){
		inv[i-1]=inv[i]*1ll*i%mod;
	}
}
il int C(int x,int y){
	return x<y||y<0?0:fac[x]*1ll*inv[y]%mod*inv[x-y]%mod;
}
int main(){
	freopen("sor.in","r",stdin);
	freopen("sor.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		tong[a[i]]++;
	}
	for(int i=1;i<=V;i++){
		for(int j=i;j<=V;j+=i){
			g[i]+=tong[j];
		}
	}
	init();
	memset(ans,0x3f,sizeof(ans));
	for(int t=1;t<=7;t++){
		for(int i=V;i;i--){
			f[i]=C(g[i],t);
			for(int j=i<<1;j<=V;j+=i){
				sub(f[i],f[j]);
			}
			if(f[i]){
				ans[i]=min(ans[i],t);
			}
		}
	}
	for(int i=1;i<=m;i++){
		if(ans[i]>=inf){
			cout<<-1<<' '<<-1<<'\n';
		}else{
			cout<<ans[i]<<' '<<g[i]<<'\n';
		}
	}
	return 0;
}
}
int main(){return asbt::main();}

C. 尘埃下的神话

D. 怪盗德基

2025.11.08 NOIP2025模拟4

A B C D Sum Rank
100 40 65 - 205 4/24

听了 zwh 的建议决定记录日期,因为教练老是改比赛名字🐱‍💻

A. 括号问号

首先考虑对于一个确定的字符串求 \(f(S)\),设 \(dp_{i,j}\) 表示考虑到 \(i\),多出来 \(j\)( 的方案数,有转移:

\[dp_{i,j}=\begin{cases} \begin{aligned} &dp_{i-1,j-1}&s_i='('\\ &dp_{i-1,j+1}&s_i=')'\\ &dp_{i-1,j-1}+dp_{i-1,j+1}&s_i='?' \end{aligned} \end{cases} \]

考虑对每个子序列求和,设 \(dp_{i,j,k}\) 表示考虑到 \(i\)\(i\) 是当前子序列的第 \(j\) 位,多出来 \(k\)( 的方案数,转移是类似的。注意到第二维只会从 \(j-1\) 转移到 \(j\),可以直接去掉。然后再前缀和优化一下即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
using namespace std;
namespace asbt{
const int maxn=5e3+5,mod=998244353;
il int pls(int x,int y){
	return x+y<mod?x+y:x+y-mod;
}
il void add(int &x,int y){
	x=pls(x,y);
}
il int mns(int x,int y){
	return x<y?x-y+mod:x-y;
}
il void sub(int &x,int y){
	x=mns(x,y);
}
int n,f[maxn][maxn];
string s;
int main(){
	freopen("bracket.in","r",stdin);
	freopen("bracket.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>s;
	s=" "+s;
	f[0][0]=1;
	for(int i=1;i<=n;i++){
		for(int j=0;j<=i;j++){
			if(s[i]=='('){
				f[i][j]=pls(f[i-1][j],j?f[i-1][j-1]:0);
			}else if(s[i]==')'){
				f[i][j]=pls(f[i-1][j],f[i-1][j+1]);
			}else{
				f[i][j]=pls(f[i-1][j],pls(j?f[i-1][j-1]:0,f[i-1][j+1]));
			}
		}
	}
	cout<<f[n][0];
	return 0;
}
}
int main(){return asbt::main();}

B. 狗卡

考虑从总贡献中减去损失的贡献,即如果存在英雄在 \(t\) 时刻完成了升级则将贡献减去 \(t\)

于是我们要做的就是将 \(n\) 个数组 \(a_{i,j}\) 重排到另一个数组 \(b_i\) 中,使得在 \(b\) 中满足 \(a\) 中的顺序,所有前缀和的和最小。考虑两端在 \(a\) 中连续的 \(x\)\(y\),则 \(x\)\(y\) 的前面的充要条件就是 \(x\) 的平均值小于 \(y\)。于是我们要将每个 \(a_i\) 分段,使得每一段的平均值都尽可能的小。考虑 \(a\) 的前缀和数组 \(s\),对于每个 \(i\),我们会有 \(k_i\) 个点 \((j,s_j)\),而两点之间的斜率就是这一段的平均值。考虑最后每一段的平均值都最小,则必然斜率递增,于是我们维护一个下凸包即可。然后就不断将每个 \(i\) 的最前面一段丢进优先队列即可。注意这里不要使用 queue,因为它的底层实现是 deque,内存是分段连续的多个固定大小的数组块,空间占用巨大。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pb push_back
using namespace std;
namespace asbt{
const int maxn=6e5+5,maxm=1.2e6+5;
int n,b[maxn],s[maxm],p[maxn];
ll m,c[maxm];
vector<int> a[maxn];
struct node{
	int i,l,r,len;
	ll sum;
	node(int i=0,int l=0,int r=-1,ll sum=0):i(i),l(l),r(r),len(r-l+1),sum(sum){}
	il bool operator<(const node &x)const{
		return sum*x.len>x.sum*len;
	}
};
vector<node> d[maxn];
priority_queue<node> q;
int main(){
	freopen("dog.in","r",stdin);
	freopen("dog.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>b[i];
		a[i].resize(b[i]+1);
		int top=0;
		s[++top]=0;
		for(int j=1;j<=b[i];j++){
			cin>>a[i][j];
			c[j]=c[j-1]+a[i][j];
			while(top>1&&(c[j]-c[s[top]])*(s[top]-s[top-1])<=(c[s[top]]-c[s[top-1]])*(j-s[top])){
				top--;
			}
			s[++top]=j;
		}
		for(int j=2;j<=top;j++){
			d[i].pb(node(i,s[j-1]+1,s[j],c[s[j]]-c[s[j-1]]));
		}
		q.push(d[i].front()),p[i]=1;
	}
//	puts("666");
//	return 0;
	ll ans=0,cur=0,sum=0;
	while(q.size()){
		node t=q.top();
		q.pop();
		for(int i=t.l;i<=t.r;i++){
			ans+=cur*a[t.i][i],cur++,sum+=a[t.i][i];
		}
		if(p[t.i]<d[t.i].size()){
			q.push(d[t.i][p[t.i]]),p[t.i]++;
		}
	}
	cout<<ans+(m-sum)*cur;
	return 0;
}
}
signed main(){return asbt::main();}

C. 均衡区间

首先求出 \(i\) 左/右侧第一个比 \(a_i\) 大/小的位置 \(sl_i,gl_i,sr_i,gr_i\)。于是对于一个合法的区间 \([i,j]\),必然有 \(i<\min(sl_j,gl_j)\land j>\max(sr_i,gr_i)\)。而这个条件显然也是充分的,直接二维数点即可。

Code
#include<bits/stdc++.h>
#define ll long long
#define il inline
#define pii pair<int,int>
#define mp make_pair
#define fir first
#define sec second
using namespace std;
namespace asbt{
const int maxn=1e6+5,inf=2e9;
int n,T,a[maxn],sl[maxn],gl[maxn],sr[maxn],gr[maxn],s[maxn],ans[maxn];
pii b[maxn];
struct{
	#define lowbit(x) (x&-x)
	int tr[maxn];
	il void clear(){
		memset(tr,0,sizeof(tr));
	}
	il void add(int p,int x){
		for(;p<=n+1;p+=lowbit(p)){
			tr[p]+=x;
		}
	}
	il int query(int p){
		int res=0;
		for(;p;p-=lowbit(p)){
			res+=tr[p];
		}
		return res;
	}
	#undef lowbit
}F;
il void work(){
	int t=0;
	s[0]=0;
	for(int i=1;i<=n;i++){
		while(t&&a[s[t]]>=a[i]){
			t--;
		}
		sl[i]=s[t];
		s[++t]=i;
	}
	t=0;
	for(int i=1;i<=n;i++){
		while(t&&a[s[t]]<=a[i]){
			t--;
		}
		gl[i]=s[t];
		s[++t]=i;
	}
	s[0]=n+1,t=0;
	for(int i=n;i;i--){
		while(t&&a[s[t]]>=a[i]){
			t--;
		}
		sr[i]=s[t];
		s[++t]=i;
	}
	t=0;
	for(int i=n;i;i--){
		while(t&&a[s[t]]<=a[i]){
			t--;
		}
		gr[i]=s[t];
		s[++t]=i;
	}
//	for(int i=1;i<=n;i++){
//		cout<<i<<' '<<sl[i]<<' '<<gl[i]<<' '<<sr[i]<<' '<<gr[i]<<'\n';
//	}
	for(int i=1;i<=n;i++){
		b[i]=mp(min(sl[i],gl[i]),i);
	}
	sort(b+1,b+n+1);
	int p=n;
	F.clear();
	for(int i=n;i;i--){
		while(p&&b[p].fir>i){
			F.add(b[p--].sec,1);
		}
		ans[i]=F.query(n+1)-F.query(max(sr[i],gr[i]));
	}
}
int main(){
	freopen("interval.in","r",stdin);
	freopen("interval.out","w",stdout);
	ios::sync_with_stdio(0),cin.tie(0);
	cin>>n>>T;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	work();
	for(int i=1;i<=n;i++){
		cout<<ans[i]<<' ';
	}
	cout<<'\n';
	reverse(a+1,a+n+1);
	work();
	for(int i=n;i;i--){
		cout<<ans[i]<<' ';
	}
	return 0;
}
}
int main(){return asbt::main();}

D. 喵了个喵了个喵

posted @ 2025-11-06 17:26  zhangxy__hp  阅读(12)  评论(0)    收藏  举报