noip模拟4
A Median
打了 分,但是因为 printf("%.1lf")
惨遭爆零。
原因详见我写的讨论。
首先,你需要把 范围是质数全部筛出来,大概耗时半秒。
然后,考虑数据是根据质数构造的,所以近似为随机。
那么既然随机,那咱们直接对于每次移动去维护中位数的位置就好了。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long const int N=1.1e7+7,M=5e5+5,K=180000000; //180000000 bitset<K>vis; bitset<K>isp,p1; int p[N]; int ccnt; int ans; inline void init(int n) { for(int i=2;i<=n;i++) { if(!vis[i]) p[++ccnt]=i; for(int j=1;1ll*i*p[j]<=n;j++) { vis[i*p[j]]=1; if(i%p[j]==0) break; } } } int n,k,w; int s[N],s2[N]; int sub[N]; const int mx=1e7; int cnt[N]; namespace sub1{ inline void init2(int n) { for(int i=2;i<=n;i++) { if(!isp[i]) { p1[++ccnt]=(i%3==2?1:0); for(int j=2;j*i<=n;j++) isp[j*i]=1; } } } int c[6]; void Q() { init2(180000000); p1[2]=0,p1[1]=2,s2[0]=5; for(int i=1;i<=n;i++) { if(i==2) { s[i]=0,s2[i]=s[i/10+1]; continue; } s[i]=((p1[i]==1?2:1)*i)%w; s2[i]=s[i]+s[i/10+1]; } for(int i=0;i<k;i++)c[s2[i]]++; double ans=0; for(int i=1;i<=n-k+1;i++) { c[s2[i-1]]--,c[s2[i+k-1]]++; if(k%2==1) { int mid=(k+1)/2,lcnt=0,j=0; for(;j<=4;j++) { lcnt+=c[j]; if(lcnt>=mid) break; } ans+=j; } else { int mid=k>>1,lcnt=0,j=0; double res=0; for(;j<=4;j++) { lcnt+=c[j]; if(lcnt>mid) { res=j;break; } else if(lcnt==mid) { int k=j+1; while(!c[k])k++; res+=(double)(j+k)/2.0; break; } } ans+=res; } } printf("%.1f",ans); exit(0); } } signed main() { freopen("median.in","r",stdin); freopen("median.out","w",stdout); ios::sync_with_stdio(false),cin.tie(0),cout.tie(0); cin>>n>>k>>w; if(w==3)sub1::Q(); init(180000000); for(int i=1;i<=n;i++) s[i]=(p[i]*i%w),s2[i]=s[i]+s[i/10+1]; for(int i=1;i<=k;i++) cnt[s2[i]]++; if(k&1) { int sum=0,tp1=0,tp2=0,cnt1=0,cnt2=0; for(int i=1;i<=mx;i++) { sum+=cnt[i]; if(sum>=k/2+1) { cnt1=sum-cnt[i],cnt2=k-sum; tp1=tp2=i; break; } if(cnt[i]) tp1=i; } ans+=tp1+tp2; int num=k/2; for(int i=1;i<=n-k;i++) { int lst=s2[i],now=s2[i+k]; cnt[lst]--,cnt[now]++; cnt1+=-(lst<tp1)+(now<tp1); cnt2+=-(lst>tp1)+(now>tp1); while(cnt1>num) cnt2+=cnt[tp1],tp1--,cnt1-=cnt[tp1]; while(cnt2>num) cnt1+=cnt[tp1],tp1++,cnt2-=cnt[tp1]; ans+=tp1*2; } } else { int num=k/2,cnt1=0,cnt2=0; int tp1=-1,tp2=-1; for(int i=k;i<=n;i++) { if(i!=k) cnt[s2[i]]++; if(s2[i]<=tp1) cnt1++; if(s2[i]<=tp2) cnt2++; if(i>k) { cnt[s2[i-k]]--; if(s2[i-k]<=tp1) cnt1--; if(s2[i-k]<=tp2) cnt2--; } while(cnt1<num) cnt1+=cnt[++tp1]; while(cnt2<=num) cnt2+=cnt[++tp2]; while(cnt1>=num+cnt[tp1]) cnt1-=cnt[tp1--]; while(cnt2>=num+1+cnt[tp2]) cnt2-=cnt[tp2--]; ans+=tp1+tp2; } } if(ans&1) cout<<ans/2<<".5"; else cout<<ans/2<<".0"; }
B Game
太可恶了。考场上差点打出来,结果忽然不想打了,痛失 50。
做法是显然的。拿优先队列每次取出队头久好了。
但是 不能接受啊。
那其实我们可以从值域下手。
维护最大值,每次暴力地看最大值是否被修改,如果修改,则更新最大值。
这时候最大值只可能是被取走,因为如果当前值比最大值还要大,那么你会优先取走这个。
因此,序列中维护的最大值是单调不增的。
那我们维护一次就是 ,总复杂度 。
点击查看代码
#include<bits/stdc++.h> using namespace std; #define int long long int n,k; const int N=1e6+6; int a[N], t[N]; signed main() { freopen("game.in","r",stdin); freopen("game.out","w",stdout); ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]; while(k--) { int cnta=0,cntb=0; int p;cin>>p; int mx=0; for(int i=1;i<p;i++) t[a[i]]++,mx=max(mx,a[i]); int stp=0; for(int i=p;i<=n;i++) { stp++; if(a[i]>=mx) stp%2==1?cnta+=a[i]:cntb+=a[i]; else { t[a[i]]++,t[mx]--; (stp)%2==1?cnta+=mx:cntb+=mx; while(!t[mx])--mx; } } for(int i=mx;i>=1;i--) { while(t[i]) { (++stp)%2==1?cnta+=i:cntb+=i; t[i]--; } } cout<<cnta-cntb<<"\n"; } return 0; }
C Park
树形 dp,我不会。
点击查看代码
#include <bits/stdc++.h> #define int long long using namespace std; inline int read(){ register char ch=getchar();register int x=0; while(ch<'0'||ch>'9')ch=getchar(); while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return x; } const int N=1e5+5,V=105; int n,v,ans,a[N],f[N][V][2],g[N][V][2]; vector<int>G[N]; void dfs(int x,int p){ f[x][0][1]=g[x][0][1]=-1e16; int sum=0; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(y==p)continue; dfs(y,x); sum+=a[y]; } g[x][1][1]=sum+a[p]; for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(y==p)continue; int mxf=-1e16,mxg=-1e16; for(int j=v;j>=0;j--){ mxf=max(mxf,max(f[x][v-j][0],f[x][v-j][1]+a[p]-a[y])), mxg=max(mxg,max(g[x][v-j][0],g[x][v-j][1])); ans=max(ans,mxg+max(f[y][j][0],f[y][j][1])); ans=max(ans,mxf+max(g[y][j][0],g[y][j][1])); } for(int j=1;j<=v;j++){ f[x][j][0]=max(f[x][j][0],max(f[y][j][0],f[y][j][1])), g[x][j][0]=max(g[x][j][0],max(g[y][j][0],g[y][j][1])); f[x][j][1]=max(f[x][j][1],max(f[y][j-1][0],f[y][j-1][1])+sum), g[x][j][1]=max(g[x][j][1],max(g[y][j-1][0],g[y][j-1][1])+sum-a[y]+a[p]); } } } signed main(){ freopen("park.in","r",stdin); freopen("park.out","w",stdout); n=read(),v=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1,u,v;i<n;i++){ u=read(),v=read(); G[u].push_back(v); G[v].push_back(u); } dfs(1,0); cout<<ans; }
D 路径
变形金刚。
我只会 , 暴力和 的 dp。。。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!