2024初三年前集训测试3
2024初三年前集训测试3
\(T1\) 夕景昨日 \(90pts\)
-
部分分
- \(10pts\) :输出
No
。 - \(20pts\) : \(O(2^{n})\) 的 \(DFS\) 暴力枚举能得到的所有数,用
map
里进行判断。 - \(90pts\) :输出
Yes
。
- \(10pts\) :输出
-
正解
- 观察到 \(1 \le n \le 100000,0 \le a_{i} \le 500000\) 。
- 猜测 \(n\) 到达一定数量级时,一定有解。
- \(n\) 个数最多产生 \(2^{n}\) 个数, \(a_{i}\) 最多配对出 \(nV\) 个数。经打表,枚举 \(V=1 \sim 500000\) 解关于 \(n\) 的不等式 \(2nV \le 2^{n}\) ,解得当 \(V=500000\) 时,\(n\) 的最小整数解为 \(25\) 。
- 严格意义上来说,极限数据应该造成 \(1,2,4,8,16,32, \dots\) 。
- 故当 \(n \le 25\) 时,仍选择用 \(DFS\) 暴力枚举;否则,一定有解。
点击查看代码
ll a[100001],flag=0; map<ll,ll>vis; void dfs(ll x,ll now,ll n) { if(x==n) { vis[now]++; if(vis[now]==2) { flag=1; } } else { dfs(x+1,now+a[x+1],n); dfs(x+1,now-a[x+1],n); } } int main() { ll n,i; cin>>n; for(i=1;i<=n;i++) { cin>>a[i]; } if(n<=25) { dfs(0,0,n); if(flag==0) { cout<<"No"<<endl; } else { cout<<"Yes"<<endl; } } else { cout<<"Yes"<<endl; } return 0; }
\(T2\) 透明答案 \(70pts\)
- 部分分
- \(30pts\) :输出
Bob
。 - \(70pts\) :输出
Ayano
。
- \(30pts\) :输出
- 正解
- 博弈论
-
弱化
- 删去“此外,每 \(3\) 回合他们会添加一堆石子(含 \(2\) 块石子)。换句话说,在第 \(t\) 次操作(两个人操作的总次数)之后,如果可以被 \(3\) 整除,则添加一堆 \(2\) 块石子的石子堆。(即使在第 \(t\) 次操作中取完了所有石子,如果 \(t\) 可被 \(3\) 整除,也会添加新石子堆并继续游戏。)”,其他部分不变。
- 由 \(NIM\) 博弈,有
Ayano
获胜当且仅当 \(\bigoplus\limits_{i=1}^{n}a_{i}=0\) 时,即 \(n \equiv 0 \pmod{2}\) ;否则,有Bob
获胜。
-
手动模拟
- 当 \(n=1\) 时,有
Ayano
获胜。 - 当 \(n=2\) 时,有
Bob
获胜。 - 当 \(n=3\) 时,有
Ayano
获胜。
- 当 \(n=1\) 时,有
-
推广
- 将 \(n\) 拆成 \(n=\left\lfloor \dfrac{n}{3} \right\rfloor \times 3+n \bmod 3\) 。前面 \(\left\lfloor \dfrac{n}{3} \right\rfloor \times 3\) 堆答案不造成影响,对答案造成影响的只有 \(n \bmod 3\) 。故当 \(n \equiv 2 \pmod{3}\) 时,有
Bob
获胜。 否则,有Ayano
获胜。
点击查看代码
int main() { int n; cin>>n; if(n%3==2) { cout<<"Bob"<<endl; } else { cout<<"Ayano"<<endl; } return 0; }
- 将 \(n\) 拆成 \(n=\left\lfloor \dfrac{n}{3} \right\rfloor \times 3+n \bmod 3\) 。前面 \(\left\lfloor \dfrac{n}{3} \right\rfloor \times 3\) 堆答案不造成影响,对答案造成影响的只有 \(n \bmod 3\) 。故当 \(n \equiv 2 \pmod{3}\) 时,有
-
- \(DFS\)
- 出题人称因是普及难度的比赛,所以把 \(DFS\) 放过去了。
- 博弈论
\(T3\) 界外科学 \(50pts\)
-
部分分
-
\(50pts\) :超大背包 \(O(2^{n})\) 枚举。
点击查看代码
ll a[50],b[50],ans=0; void dfs(ll x,ll worth,ll now,ll n,ll m) { if(x==n) { ans=(worth<=m)?max(ans,now):ans; } else { dfs(x+1,worth^a[x+1],now+b[x+1],n,m); dfs(x+1,worth,now,n,m); } } int main() { ll n,m,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=n;i++) { cin>>b[i]; } dfs(0,0,0,n,m); cout<<ans<<endl; return 0; }
-
\(100pts\)
-
输出 \(\sum\limits_{i=1}^{n}b_{i}\) 。
-
超大背包 \(O(2^{n})\) 的玄学优化,优化后时间复杂度未知。
点击查看代码
ll a[50],b[50],sum[50],ans=0; void dfs(ll x,ll worth,ll now,ll n,ll m) { if(x==n) { ans=(worth<=m)?max(ans,now):ans; } else { if(now+sum[n]-sum[x]>ans) { dfs(x+1,worth^a[x+1],now+b[x+1],n,m); } if(now+sum[n]-sum[x+1]>ans) { dfs(x+1,worth,now,n,m); } } } int main() { ll n,m,i; cin>>n>>m; for(i=1;i<=n;i++) { cin>>a[i]; } for(i=1;i<=n;i++) { cin>>b[i]; sum[i]=sum[i-1]+(b[i]>0)*b[i]; } dfs(0,0,0,n,m); cout<<ans<<endl; return 0; }
-
面向数据点分治,当 \(n\) 较大时,选择 \(nV\) 的 \(01\) 背包做法。
- 这里背包不能滚成一维。
-
-
-
正解
点击查看官方题解
\(T4\) 回忆补时 \(30pts\)
-
部分分
-
\(30pts\) : \(O(n^{2}q)\) 暴力枚举。
点击查看代码
ll k[100001],b[100001]; int main() { ll n,q,x,ans,i,j,h; scanf("%lld",&n); for(i=1;i<=n;i++) { scanf("%lld%lld",&k[i],&b[i]); } scanf("%lld",&q); for(i=1;i<=q;i++) { scanf("%lld",&x); ans=0; for(j=1;j<=n;j++) { for(h=j+1;h<=n;h++) { ans=max(ans,max(k[h]*(k[j]*x+b[j])+b[h],k[j]*(k[h]*x+b[h])+b[j])); } } printf("%lld\n",ans); } return 0; }
-
\(60pts\) :当 \(k_{j} \ge 0\) 时,\(k_{i}x+b_{i}\) 越大对答案的贡献越大;当 \(k_{j}<0\) 时,\(k_{i}x+b_{i}\) 越小对答案的贡献越小。考虑计算出 \(k_{i}x+b_{i}\) 的最大值、次大值、最小值、次小值,然后进行转移。
点击查看代码
ll k[100001],b[100001]; int main() { ll n,q,x,ans,zmax,cmax,zmin,cmin,idzmax,idzmin,i,j; cin>>n; for(i=1;i<=n;i++) { cin>>k[i]>>b[i]; } cin>>q; for(i=1;i<=q;i++) { cin>>x; ans=zmax=cmax=idzmax=idzmin=0; zmin=cmin=0x7f7f7f7f; for(j=1;j<=n;j++) { if(k[j]*x+b[j]>zmax) { cmax=zmax; zmax=k[j]*x+b[j]; idzmax=j; } else { cmax=max(cmax,k[j]*x+b[j]); } if(k[j]*x+b[j]<zmin) { cmin=zmin; zmin=k[j]*x+b[j]; idzmin=j; } else { cmin=min(cmin,k[j]*x+b[j]); } } for(j=1;j<=n;j++) { if(k[j]>=0) { ans=max(ans,(j==idzmax)?cmax*k[j]+b[j]:zmax*k[j]+b[j]); } else { ans=max(ans,(j==idzmin)?cmin*k[j]+b[j]:zmin*k[j]+b[j]); } } cout<<ans<<endl; } return 0; }
-
-
正解
点击查看官方题解
总结
- 打到 \(8:40\) 就去打矩阵快速幂了。
- 要学会通过值域猜测时间复杂度和判断答案范围。
后记
- 普及模拟赛考博弈论、折半搜索、李超线段树,难评。
- 没有大样例,差评。
- 建议本场比赛改名为暴力骗分/良心送分模拟赛。
本文来自博客园,作者:hzoi_Shadow,原文链接:https://www.cnblogs.com/The-Shadow-Dragon/p/18008439,未经允许严禁转载。
版权声明:本作品采用 「署名-非商业性使用-相同方式共享 4.0 国际」许可协议(CC BY-NC-SA 4.0) 进行许可。