2024初三集训模拟测试4
2024初三集训模拟测试4
\(T1\) 打赌 \(0pts\)
-
模拟即可。
点击查看代码
int main() { freopen("pogodak.in","r",stdin); freopen("pogodak.out","w",stdout); ll n,m,ans=0,u=1,d=6,f=2,b=5,l=4,r=3,lsu,lsd,lsf,lsb,lsl,lsr,i,j; cin>>n>>m; for(i=1;i<=n;i++) { if(i%2==1) { ans+=m/4*(u+d+l+r); for(j=1;j<=m%4;j++) { if(j!=1) { lsu=u; lsd=d; lsl=l; lsr=r; u=lsl; d=lsr; l=lsd; r=lsu; } ans+=u; } lsu=u; lsd=d; lsf=f; lsb=b; u=lsb; d=lsf; f=lsu; b=lsd; } else { ans+=m/4*(u+d+l+r); for(j=1;j<=m%4;j++) { if(j!=1) { lsu=u; lsd=d; lsl=l; lsr=r; u=lsr; d=lsl; l=lsu; r=lsd; } ans+=u; } lsu=u; lsd=d; lsf=f; lsb=b; u=lsb; d=lsf; f=lsu; b=lsd; } } cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
\(T2\) 舞会 \(0pts\)
-
从贪心角度的分析,将正整数的男孩与负整数的女孩进行配对,负整数的男孩与正整数的女孩进行配对时,要尽可能地选择接近的数。排序后使用双指针维护即可。
点击查看代码
ll a[2][200000],b[2][200000]; int main() { freopen("party.in","r",stdin); freopen("party.out","w",stdout); ll n,x,n1=0,n2=0,n3=0,n4=0,ans=0,l,r,i; cin>>n; for(i=1;i<=n;i++) { cin>>x; if(x<0) { n1++; a[0][n1]=-x; } else { n2++; a[1][n2]=x; } } for(i=1;i<=n;i++) { cin>>x; if(x<0) { n3++; b[0][n3]=-x; } else { n4++; b[1][n4]=x; } } sort(a[0]+1,a[0]+1+n1); sort(a[1]+1,a[1]+1+n2); sort(b[0]+1,b[0]+1+n3); sort(b[1]+1,b[1]+1+n4); for(l=1,r=1;l<=n1&&r<=n4;l++,r++) { while(l<=n1&&a[0][l]<=b[1][r]) { l++; } ans+=(l<=n1); } for(l=1,r=1;l<=n2&&r<=n3;l++,r++) { while(r<=n3&&a[1][l]>=b[0][r]) { r++; } ans+=(r<=n3); } cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
\(T3\) 最小生成树 \(0pts\)
-
经打表,有最小生成树的边权和为 \(n-1\) ,构造每条边上的两端点互质即可。
-
故 \(\prod\limits_{i=1}^{n}\varphi(i)\) 即为所求。
点击查看代码
const ll p=100000007; ll phi[40000],prime[40000],vis[40000],len=0; void euler(ll n) { memset(vis,0,sizeof(vis)); phi[1]=1; for(ll i=2;i<=n;i++) { if(vis[i]==false) { len++; prime[len]=i; phi[i]=i-1; } for(ll j=1;j<=len&&i*prime[j]<=n;j++) { vis[i*prime[j]]=1; if(i%prime[j]==0) { phi[i*prime[j]]=phi[i]*prime[j]; break; } else { phi[i*prime[j]]=phi[i]*(prime[j]-1); } } } } int main() { freopen("mst.in","r",stdin); freopen("mst.out","w",stdout); ll n,ans=1,i; cin>>n; euler(n); for(i=1;i<=n;i++) { ans=ans*phi[i]%p; } cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
\(T4\) 买汽水 \(100pts\)
-
部分分
- \(50pts\)
-
超大背包,暴力 \(DFS\) 枚举每天买或不买饮料。
-
时间复杂度为 \(O(2^{n})\) 。
点击查看代码
ll p[50],ans=0; void dfs(ll x,ll n,ll m,ll worth) { if(x==n+1) { if(worth<=m) { ans=max(ans,worth); } } else { if(worth+p[x]<=m) { dfs(x+1,n,m,worth+p[x],worth+p[x]); } dfs(x+1,n,m,worth); } } int main() { freopen("drink.in","r",stdin); freopen("drink.out","w",stdout); ll n,m,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>p[i]; } dfs(1,n,m,0); cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
-
- \(60pts\) :输出 \(m\) 。
- \(50pts\)
-
正解
- 考虑优化搜索过程,使用双向搜索。具体地,对于 \([1,\left\lfloor \frac{n}{2}\right\rfloor]\) 进行第一遍搜索,对于得到的价值存到一个
set
里面。对于 \([\left\lfloor \frac{n}{2}\right\rfloor+1,n]\) 进行第二遍搜索,对于得到的价值在set
里面找到满足 \(\le m-\) 当前重量的最大价值,进行转移即可。 - 时间复杂度为 \(O(2^{\frac{n}{2}}n)\) 。
点击查看代码
set<ll>vis; ll p[50],ans=0; void dfsl(ll x,ll n,ll m,ll worth) { if(x==n+1) { if(worth<=m) { vis.insert(worth); } } else { if(worth+p[x]<=m) { dfsl(x+1,n,m,worth+p[x]); } dfsl(x+1,n,m,worth); } } void dfsr(ll x,ll n,ll m,ll worth) { if(x==n+1) { if(worth<=m) { ans=max(ans,worth+(*(--vis.upper_bound(m-worth)))); } } else { if(worth+p[x]<=m) { dfsr(x+1,n,m,worth+p[x]); } dfsr(x+1,n,m,worth); } } int main() { freopen("drink.in","r",stdin); freopen("drink.out","w",stdout); ll n,m,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>p[i]; } dfsl(1,n/2,m,0); dfsr(n/2+1,n,m,0); cout<<ans<<endl; fclose(stdin); fclose(stdout); return 0; }
- 考虑优化搜索过程,使用双向搜索。具体地,对于 \([1,\left\lfloor \frac{n}{2}\right\rfloor]\) 进行第一遍搜索,对于得到的价值存到一个
总结
- 开题顺序 \(T4,T2,T1\) 。
- 要善于从题目背景中获得信息。
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18027043,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。