2024初三集训模拟测试3
2024初三集训模拟测试3
计蒜客 T3726 排序
-
考虑先将
数组进行升序排列。然后题意转化为了把 平均分成 组,使得每组乘积之和最小;把 平均分成 组,使得每组乘积之和最大。 -
对于
若存在 则有 ,若加上等于号则有 。- 其实就是 普及模拟2 T2 内积 的结论的推广。
-
故最终
即为所求。点击查看代码
ll a[500001]; int main() { ll n,ans=0,i; cin>>n; for(i=1;i<=4*n;i++) { cin>>a[i]; } sort(a+1,a+1+4*n); for(i=1;i<=n;i++) { ans-=a[i]*a[2*n-i+1]; } for(i=2*n+1;i<=4*n;i+=2) { ans+=a[i]*a[i+1]; } cout<<ans<<endl; return 0; }
计蒜客 T3727 牛吃草
-
部分分
-
为使最小覆盖大小最大,考虑二分答案,设当前二分出来的答案为
。 -
设
表示对 完成最小覆盖大小 的覆盖后的最大总覆盖大小,状态转移方程为 。暴力进行转移即可。点击查看代码
int w[600000],f[600000]; bool check(int mid,int n,int m) { int i,j; memset(f,0,sizeof(f)); for(i=1;i<=n;i++) { f[i]=f[i-1]; if(i-w[i]>=0) { for(j=i-w[i];j<=i-mid;j++) { f[i]=max(f[i],f[j]+(i-j)); } } } return f[n]>=m; } int main() { int n,m,s,l=1,r,mid,i; cin>>n; for(i=1;i<=n;i++) { cin>>w[i]; } cin>>s; r=m=ceil(1.0*n*s/100); while(l<=r) { mid=(l+r)/2; if(check(mid,n,m)==true) { l=mid+1; } else { r=mid-1; } } cout<<r<<endl; return 0; }
-
-
正解
- 由于
,故 ,故当 增大时,有 的上界增加了 ,下界减少了 ,使用单调队列维护即可。
点击查看代码
int w[600000],f[600000]; bool check(int mid,int n,int m) { deque<int>q; for(int i=1;i<=n;i++) { f[i]=f[i-1]; if(i-mid>=0) { while(q.empty()==0&&f[q.back()]-q.back()<=f[i-mid]-(i-mid)) { q.pop_back(); } q.push_back(i-mid); while(q.empty()==0&&q.front()<=i-w[i]-1) { q.pop_front(); } if(q.empty()==0) { f[i]=max(f[i],f[q.front()]-q.front()+i); } } } return f[n]>=m; } int main() { int n,m,s,l=1,r,mid,i; cin>>n; for(i=1;i<=n;i++) { cin>>w[i]; } cin>>s; r=n; m=ceil(1.0*n*s/100); check(1,n,m); while(l<=r) { mid=(l+r)/2; if(check(mid,n,m)==true) { l=mid+1; } else { r=mid-1; } } cout<<r<<endl; return 0; }
- 由于
计蒜客 T3728 树上的宝藏
-
部分分
:设 分别表示以 为根节点的子树内,不选和选 的方案数。状态转移方程为 。对于一条边 ,砍断这条边后,进行树形 ,此时 即为所求。
-
正解
- 发现砍断操作可以用换根
优化。- 钦定
为根节点。 - 第一遍
时,处理出 。 - 第二遍
时,进行换根。设 表示以 为整棵树的根节点时,不选和选 的方案数,仍钦定 为根节点。考虑根节点由 变为 的过程中,以 为根的子树内的节点对答案的贡献不变,要消除以 为根的子树内的节点对以 为根的子树的影响,故状态转移方程为 。
- 钦定
- 对于一条边
,进行分类讨论。- 若不选
,选 ,则有 即为所求。 - 若选
,不选 ,则有 即为所求。 - 若选
,则有 即为所求。
- 若不选
点击查看代码
const ll p=998244353; struct node { ll nxt,to; }e[700000]; ll head[700000],dep[700000],u[700000],v[700000],g[700000][2],f[700000][2],cnt=0; void add(ll u,ll v) { cnt++; e[cnt].nxt=head[u]; e[cnt].to=v; head[u]=cnt; } ll qpow(ll a,ll b,ll p) { ll ans=1; while(b>0) { if(b&1) { ans=ans*a%p; } b>>=1; a=a*a%p; } return ans; } void dfs(ll x,ll fa) { f[x][0]=f[x][1]=1; dep[x]=dep[fa]+1; for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa) { dfs(e[i].to,x); f[x][0]=f[x][0]*((f[e[i].to][0]+f[e[i].to][1])%p)%p; f[x][1]=f[x][1]*f[e[i].to][0]%p; } } } void reroot(ll x,ll fa) { if(x!=1) { ll f0=g[fa][0]*qpow((f[x][0]+f[x][1])%p,p-2,p)%p,f1=g[fa][1]*qpow(f[x][0],p-2,p)%p; g[x][0]=f[x][0]*((f0+f1)%p)%p; g[x][1]=f[x][1]*f0%p; } for(ll i=head[x];i!=0;i=e[i].nxt) { if(e[i].to!=fa) { reroot(e[i].to,x); } } } int main() { ll n,sum1,sum2,sum3,i; cin>>n; for(i=1;i<=n-1;i++) { cin>>u[i]>>v[i]; add(u[i],v[i]); add(v[i],u[i]); } dfs(1,0); g[1][0]=f[1][0]; g[1][1]=f[1][1]; reroot(1,0); for(i=1;i<=n-1;i++) { if(dep[v[i]]<dep[u[i]]) { swap(u[i],v[i]); } sum1=((f[v[i]][1]*g[u[i]][0])%p)*qpow((f[v[i]][0]+f[v[i]][1])%p,p-2,p)%p; sum2=g[u[i]][1]; sum3=((f[v[i]][1]*g[u[i]][1])%p)*qpow(f[v[i]][0]%p,p-2,p)%p; cout<<(((sum1+sum2)%p)+sum3)%p<<endl; } return 0; }
- 发现砍断操作可以用换根
计蒜客 T3729 MEX
-
Special Judge
: luogu P4137 Rmq Problem / mex -
部分分
-
-
对于每个区间枚举左右端点,进行暴力求解。
点击查看代码
ll a[5000000],vis[5000000],ans[5000000]; int main() { ll n,m,p,q,l,r,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } for(l=1;l<=n;l++) { for(r=l;r<=n;r++) { for(i=l;i<=r;i++) { vis[a[i]]=1; } for(i=0;i<=m;i++) { if(vis[i]==0) { ans[i]++; break; } } for(i=0;i<=m;i++) { vis[i]=0; } } } cin>>p>>q; for(i=p;i<=q;i++) { cout<<ans[i]<<" "; } return 0; }
-
-
-
使用莫队进行统计答案。
点击查看代码
int a[3000010],cnt[3000010],lscnt[3000010],ans[3000010],L[3000010],R[3000010],pos[3000010],klen,ksum; struct ask { int l,r,id; }q[3000010]; bool q_cmp(ask a,ask b) { return (pos[a.l]==pos[b.l])?(a.r>b.r):(a.l<b.l); } void init(int n,int m) { klen=n/sqrt(m)+1; ksum=n/klen; for(int i=1;i<=ksum;i++) { L[i]=R[i-1]+1; R[i]=R[i-1]+klen; } if(R[ksum]<n) { ksum++; L[ksum]=R[ksum-1]+1; R[ksum]=n; } for(int i=1;i<=ksum;i++) { for(int j=L[i];j<=R[i];j++) { pos[j]=i; } } } void add(int cnt[],int x) { cnt[a[x]]++; } void del(int cnt[],int x,int &sum) { cnt[a[x]]--; sum=(cnt[a[x]]==0)?min(sum,a[x]):sum; } int main() { int n,mm,m=0,x,y,l=1,r,anss=0,sum=0,tmp=0,lastblock=0,i,j; cin>>n>>mm; r=n; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=n;i++) { for(j=i;j<=n;j++) { m++; q[m].l=i; q[m].r=j; q[m].id=m; } } init(n,m); sort(q+1,q+1+m,q_cmp); for(i=1;i<=n;i++) { add(cnt,i); } while(cnt[anss]>=1) { anss++; } for(i=1;i<=m;i++) { if(pos[q[i].l]==pos[q[i].r]) { sum=0; for(j=q[i].l;j<=q[i].r;j++) { add(lscnt,j); } while(lscnt[sum]>=1) { sum++; } for(j=q[i].l;j<=q[i].r;j++) { lscnt[a[j]]--; } } else { if(lastblock!=pos[q[i].l]) { while(r<n) { r++; add(cnt,r); } while(l<L[pos[q[i].l]]) { del(cnt,l,anss); l++; } tmp=anss; lastblock=pos[q[i].l]; } while(r>q[i].r) { del(cnt,r,tmp); r--; } sum=tmp; while(l<q[i].l) { del(cnt,l,sum); l++; } while(l>L[pos[q[i].l]]) { l--; add(cnt,l); } } ans[sum]++; } cin>>x>>y; for(i=x;i<=y;i++) { cout<<ans[i]<<" "; } return 0; }
-
-
点击查看 APJifengc 写的题解
-
-
正解
点击查看 APJifengc 写的题解
原来的 std
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e6 + 5; int n, m; int arr[MAXN]; int last[MAXN]; int nxt[MAXN]; long long answer[MAXN]; struct SegmentTree { public: int min, num; long long sum; class LazyTag { public: int cover, tim; long long add; inline LazyTag() { cover = -1; add = 0; tim = 0; } inline LazyTag(const int cover):cover(cover) { add=tim=0;// Linux 下会出莫名错误,遂把这句话补上了 if (cover == -1) { tim = 1; } } } tag; } sgt[MAXN << 2]; inline void PushUp(const int now) { sgt[now].min = min(sgt[now << 1].min, sgt[now << 1 | 1].min); } void Build(const int now = 1, const int left = 0, const int right = m) { if (left == right) { sgt[now].num = sgt[now].min = last[left]; return; } Build(now << 1, left, (left + right) >> 1); Build(now << 1 | 1, ((left + right) >> 1) + 1, right); PushUp(now); } inline void Down(const SegmentTree::LazyTag tag, const int now, const int left, const int right) { sgt[now].sum += 1ll * sgt[now].num * tag.tim + tag.add; if (~tag.cover) { if (~sgt[now].tag.cover) { sgt[now].tag.add += 1ll * sgt[now].tag.cover * tag.tim + tag.add; } else { sgt[now].tag.tim += tag.tim; sgt[now].tag.add = tag.add; } sgt[now].num = sgt[now].min = tag.cover; sgt[now].tag.cover = tag.cover; } else { if (~sgt[now].tag.cover) { sgt[now].tag.add += 1ll * sgt[now].tag.cover * tag.tim; } else { sgt[now].tag.tim += tag.tim; } } } inline void PushDown(const int now, const int left, const int right) { Down(sgt[now].tag, now << 1, left, (left + right) >> 1); Down(sgt[now].tag, now << 1 | 1, ((left + right) >> 1) + 1, right); sgt[now].tag = SegmentTree::LazyTag(); } void Updata(const int now_left, const int now_right, const int cover, const int now = 1, const int left = 0, const int right = m) { if (now_right < left || right < now_left) { return; } if (now_left <= left && right <= now_right) { Down(SegmentTree::LazyTag(cover), now, left, right); return; } PushDown(now, left, right); Updata(now_left, now_right, cover, now << 1, left, (left + right) >> 1); Updata(now_left, now_right, cover, now << 1 | 1, ((left + right) >> 1) + 1, right); PushUp(now); } inline void Time() { Down(SegmentTree::LazyTag(-1), 1, 1, m); } int Find(const int now_left, const int now_right, const int val, const int now = 1, const int left = 0, const int right = m) { if (now_right < left || right < now_left || val <= sgt[now].min) { return-1; } if (left == right && now_left <= left && right <= now_right) { return left; } int result(Find(now_left, now_right, val, now << 1 | 1, ((left + right) >> 1) + 1, right)); return ~result ? result : Find(now_left, now_right, val, now << 1, left, (left + right) >> 1); } void GetAnswer(const int now = 1, const int left = 0, const int right = m) { if (left == right) { answer[left] = sgt[now].sum; return; } PushDown(now, left, right); GetAnswer(now << 1, left, (left + right) >> 1); GetAnswer(now << 1 | 1, ((left + right) >> 1) + 1, right); } int main() { scanf("%d%d", &n, &m); int last0 = 0; long long answer0 = 0; for (int i = 1; i <= n; i++) { scanf("%d", &arr[i]); if (arr[i] == 0) { answer0 += (i - last0 - 1ll) * (i - last0) >> 1; last0 = i; } } answer0 += (n - last0) * (n + 1ll - last0) >> 1; for (int i = 0; i <= m; i++) { last[i] = n + 1; } for (int i = n; i >= 1; i--) { nxt[i] = last[arr[i]]; last[arr[i]] = i; } for (int i = 1; i <= m - 1; i++) { last[i] = max(last[i], last[i - 1]); } Build(); for (int i = 1; i <= n; i++) { Time(); int f = Find(arr[i], m, nxt[i]); if (~f) { Updata(arr[i], f, nxt[i]); } } GetAnswer(); int l, r; scanf("%d%d", &l, &r); if (!l) { printf("%lld ", answer0); l = 1; } for (int i = l; i <= r; i++) { printf("%lld ", answer[i] - answer[i - 1]); } return 0; }
点击查看代码
ll a[1000010],ans[1000010],last[1000010],nxt[1000010]; struct SMT { struct SegmentTree { ll len,minn,sum,hsum,cover,tlazy,hlazy; }tree[4000010]; #define lson(rt) (rt<<1) #define rson(rt) (rt<<1|1) void pushup(ll rt) { tree[rt].minn=min(tree[lson(rt)].minn,tree[rson(rt)].minn); tree[rt].sum=tree[lson(rt)].sum+tree[rson(rt)].sum; tree[rt].hsum=tree[lson(rt)].hsum+tree[rson(rt)].hsum; } void build(ll rt,ll l,ll r) { tree[rt].len=r-l+1; tree[rt].cover=-1; tree[rt].tlazy=tree[rt].hlazy=0; if(l==r) { tree[rt].minn=tree[rt].sum=last[l]; return; } ll mid=(l+r)/2; build(lson(rt),l,mid); build(rson(rt),mid+1,r); pushup(rt); } void pushlazy(ll rt,ll cover,ll tlazy,ll hlazy) { tree[rt].hsum+=tree[rt].sum*tlazy+tree[rt].len*hlazy; tree[rt].hlazy+=hlazy; if(tree[rt].cover==-1) tree[rt].tlazy+=tlazy; else tree[rt].hlazy+=tree[rt].cover*tlazy; if(cover!=-1) { tree[rt].sum=tree[rt].len*cover; tree[rt].minn=tree[rt].cover=cover; } } void pushdown(ll rt) { pushlazy(lson(rt),tree[rt].cover,tree[rt].tlazy,tree[rt].hlazy); pushlazy(rson(rt),tree[rt].cover,tree[rt].tlazy,tree[rt].hlazy); tree[rt].cover=-1; tree[rt].tlazy=tree[rt].hlazy=0; } void update(ll rt,ll l,ll r,ll x,ll y,ll val) { if(x<=l&&r<=y) { pushlazy(rt,val,0,0); return; } pushdown(rt); ll mid=(l+r)/2; if(x<=mid) update(lson(rt),l,mid,x,y,val); if(y>mid) update(rson(rt),mid+1,r,x,y,val); pushup(rt); } ll query(ll rt,ll l,ll r,ll x,ll y,ll val) { if(y<l||r<x||val<=tree[rt].minn) return -1; if(x<=l&&r<=y&&l==r) return l; ll mid=(l+r)/2,pos=query(rson(rt),mid+1,r,x,y,val); return (pos==-1)?query(lson(rt),l,mid,x,y,val):pos; } void ask(ll rt,ll l,ll r) { if(l==r) { ans[l]=tree[rt].hsum; return; } pushdown(rt); ll mid=(l+r)/2; ask(lson(rt),l,mid); ask(rson(rt),mid+1,r); } }T; int main() { // #define Isaac #ifdef Isaac freopen("in.in","r",stdin); freopen("out.out","w",stdout); #endif ll n,m,l,r,_ans=0,_last=0,pos,i; scanf("%lld%lld",&n,&m); for(i=1;i<=n;i++) { scanf("%lld",&a[i]); if(a[i]==0) { _ans+=(i-_last-1)*(i-_last)/2; _last=i; } } scanf("%lld%lld",&l,&r); _ans+=(n-_last)*(n+1-_last)/2; for(i=0;i<=m;i++) last[i]=n+1; for(i=n;i>=1;i--) { nxt[i]=last[a[i]]; last[a[i]]=i; } for(i=1;i<=m-1;i++) last[i]=max(last[i],last[i-1]); T.build(1,0,m); for(i=1;i<=n;i++) { T.pushlazy(1,-1,1,0); pos=T.query(1,0,m,a[i],m,nxt[i]); if(pos!=-1) T.update(1,0,m,a[i],pos,nxt[i]); } T.ask(1,0,m); if(l==0) { printf("%lld ",_ans); l=1; } for(i=l;i<=r;i++) printf("%lld ",ans[i]-ans[i-1]); return 0; }
总结
场上结论没有猜出来,导致心态炸了。 场上只看出来了二分答案,没有再接着去想,而且貌似还读错题了。 场上读假题了。 场上部分分没打,亏了。
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18026551,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具