【比赛记录】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=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,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();}

浙公网安备 33010602011771号