首师大附中集训第六天专题测试

2023-10-31 05:40

本文主要是介绍首师大附中集训第六天专题测试,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

专题测试

      第一题:大家都知道田忌赛马的故事,田忌和齐王又要赛马了,他们将各派出 N 匹马,每场比赛输 的一方需要给赢的一方 200 两黄金,平局的话双方都不比出钱,已知所有马的速度,且齐王 的出马顺序永远固定,求田忌的最大收益。

      有一个很显然的贪心算法,就是将它们两个序列从大到小排序,比较当前齐王最大的和田忌最大的。如果田忌的比齐王的大,那么就拿出来比。如果田忌最小的比齐王最小的大,那么直接比。否则田忌最小的就没有用了,而且没有一匹马可以打败齐王的第一匹马。就直接那田忌最小的马去拼。还是很简单的。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;int T;
int n;
int a[1010],b[1010];bool cmp(int x,int y){return x>y;
}int main(){freopen("horse.in","r",stdin);freopen("horse.out","w",stdout);scanf("%d",&T);while(T--){scanf("%d",&n);for(int i=1;i<=n;i++) scanf("%d",&a[i]);for(int i=1;i<=n;i++) scanf("%d",&b[i]);sort(a+1,a+1+n,cmp);sort(b+1,b+1+n,cmp);for(int i=1;i<=n;i++) printf("%d ",a[i]);printf("\n");for(int i=1;i<=n;i++) printf("%d ",b[i]);printf("\n");int tot=0,l1,l2,r1,r2;l1=l2=1,r1=r2=n;for(int i=1;i<=n;i++){if(a[l1]>b[l2]) tot++,l1++,l2++;else if(a[r1]>b[r2]) tot++,r1--,r2--;else{if(a[r1]<b[l2]) tot--;r1--;l2++;}}printf("%d\n",tot*200);}
}

      第二题:给出一个长度为 2N 的数字串,这个数字串中的每一位都是 0-9 的整数,其中,有一 些位置上的数是我们已知的,还有一些位置上的数未知,当且仅当这个数字串满足:前 N 个数码的乘积等于后 N 个数码的乘积的时候,我们称这个数字串是一个好的数字串,给出 一个有若干个位置未知的数字串,请你求出在未知处填上数码之后,使得这个串是一个好 的串的方案数。1≤n≤18

      想到问号并没有那么多(因为只会打暴力),所以就直接暴力枚举这个位置选什么值。然后就完了。

      把左边可能的值插进map里面,然后右边在做的时候进去查就可以了。

      为了优化时间复杂度,我们可以让两边平均,把一边的某些数移到另一边去,变成除法,至于最后答案可能很大,不会超过10^{36}。直接把它拆成两个long long即可。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#include<iostream>
#include<algorithm>
using namespace std;int n,tot1,tot2,data;
char s[40];
long long f1,f2;
long long ans1=0,ans2=0;
long long ci[20],f[20][20],c[20];
const long long block=1e18,b=1e9;
map<long long,int> mp;void times(long long x,long long y){long long x1=x/b,y1=x%b,x2=y/b,y2=y%b;ans1+=x1*x2;ans2+=y1*y2;if(x1*y2>=b) ans1+=x1*y2/b,ans2+=x1*y2%b*b;else ans2+=x1*y2*b;if(x2*y1>=b) ans1+=x2*y1/b,ans2+=x2*y1%b*b;else ans2+=x2*y1*b;ans1+=ans2/block;ans2%=block;
}void dfs_1(int x,long long coef){if(x==data+1){mp[coef]++;return ;}for(int i=1;i<=9;i++){if(x>tot1){if(coef%i!=0) continue;dfs_1(x+1,coef/i);}else dfs_1(x+1,coef*i);}
}void dfs_2(int x,long long coef){if(x==data+1){if(mp[coef]) ans2+=mp[coef];if(ans2>=block) ans1+=ans2/block,ans2%=block;return ;}for(int i=1;i<=9;i++){if(x>tot2){if(coef%i!=0) continue;dfs_2(x+1,coef/i);}else dfs_2(x+1,coef*i);}
}void calc(){ci[0]=1;for(int i=1;i<=n;i++) ci[i]=ci[i-1]*9;c[0]=1;for(int i=1;i<=n;i++) c[i]=c[i-1]*10;f[0][0]=1;for(int i=1;i<=n;i++){f[i][0]=f[i][i]=1;for(int j=1;j<i;j++) f[i][j]=f[i-1][j-1]+f[i-1][j];}long long t1=0,t2=0;if(f1==0) t1=c[tot1];else for(int i=1;i<=tot1;i++) t1+=f[tot1][i]*ci[tot1-i];if(f2==0) t2=c[tot2];else for(int i=1;i<=tot2;i++) t2+=f[tot2][i]*ci[tot2-i];times(t1,t2);
}int main(){
//	freopen("string.in","r",stdin);
//	freopen("string.out","w",stdout);scanf("%d",&n);scanf("%s",s+1);f1=f2=1;for(int i=1;i<=n;i++) if(s[i]!='?') f1*=s[i]-'0';else tot1++;for(int i=2*n;i>=n+1;i--) if(s[i]!='?') f2*=s[i]-'0';else tot2++;if(f1 && f2){data=(tot1+tot2)/2;dfs_1(1,f1);data=tot1+tot2-(tot1+tot2)/2;dfs_2(1,f2);}calc();if(ans1) printf("%lld%lld",ans1,ans2);else printf("%lld",ans2);
}

      然后就过了90。没过的那一组是因为太多问号。

      还是要讲讲正解,其实一开始差不多想出来了,但认为那个递推不能简单转移,所以就丢了。

      考虑最后相同的乘积的质因子只可能有2,3,5,7。而且2出现的次数不超过54次,3出现的次数不超过36次,5和7出现的次数不超过18次。那么直接记f[i][a][b][c][d]为把2^a3^b5^c7^d这个数填进i个空格的方案数。转移十分简单,直接枚举下一个数是什么就可以了。

      那么答案就是f[tot1][a-a_1][b-b_1][c-c_1][d-d_1]*f[tot2][a-a_2][b-b_2][c-c_2][d-d_2]

      其中tot1,tot2分别是左右两边的问号数量,a1b1c1d1是左边的已知乘积的质因数拆分,a2b2c2d2同理。

      代码补得有点恶心。(同时注意没有问号的情况)

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;int n,tot1,tot2;
char s[45];
long long f1,f2,mmax=1;
long long c[20],ci[20],C[20][20];
long long g[55][37][19][19],h[55][37][19][19];
int t[2][4];
int p[10][4];
long long f[2][55][37][19][19];
long long ans1,ans2;
const long long block=1e18,b=1e9;void times(long long x,long long y){long long x1=x/b,y1=x%b,x2=y/b,y2=y%b;ans1+=x1*x2;ans2+=y1*y2;if(x1*y2>=b) ans1+=x1*y2/b,ans2+=x1*y2%b*b;else ans2+=x1*y2*b;if(x2*y1>=b) ans1+=x2*y1/b,ans2+=x2*y1%b*b;else ans2+=x2*y1*b;ans1+=ans2/block;ans2%=block;
}void prepare(){f[0][0][0][0][0]=1;g[0][0][0][0]=1;h[0][0][0][0]=1;long long coef=1,t1,t2,t3;for(int i=1;i<=max(tot1,tot2);i++){int now=(i&1)^1;coef=1;memset(f[now^1],0,sizeof(f[now^1]));for(int a=0;a<55;a++){if(a) coef*=2;t1=coef;for(int b=0;b<37;b++){if(b) coef*=3;if(coef>mmax) break;t2=coef;for(int c=0;c<19;c++){if(c) coef*=5;if(coef>mmax) break;t3=coef;for(int d=0;d<19;d++){if(d) coef*=7;if(coef>mmax) break;for(int k=1;k<=9;k++) if(p[k][0]<=a && p[k][1]<=b && p[k][2]<=c && p[k][3]<=d)f[now^1][a][b][c][d]+=f[now][a-p[k][0]][b-p[k][1]][c-p[k][2]][d-p[k][3]];}coef=t3;}coef=t2;}coef=t1;}if(i==tot1) for(int a=0;a<55;a++)for(int b=0;b<37;b++)for(int c=0;c<19;c++)for(int d=0;d<19;d++)g[a][b][c][d]=f[now^1][a][b][c][d];if(i==tot2) for(int a=0;a<55;a++)for(int b=0;b<37;b++)for(int c=0;c<19;c++)for(int d=0;d<19;d++)h[a][b][c][d]=f[now^1][a][b][c][d];}while(f1%2==0) f1/=2,t[0][0]++;while(f1%3==0) f1/=3,t[0][1]++;while(f1%5==0) f1/=5,t[0][2]++;while(f1%7==0) f1/=7,t[0][3]++;while(f2%2==0) f2/=2,t[1][0]++;while(f2%3==0) f2/=3,t[1][1]++;while(f2%5==0) f2/=5,t[1][2]++;while(f2%7==0) f2/=7,t[1][3]++;
}void solve(){long long coef=1,t1,t2,t3;for(int a=0;a<55;a++){if(a) coef*=2;t1=coef;for(int b=0;b<37;b++){if(b) coef*=3;if(coef>mmax) break;t2=coef;for(int c=0;c<19;c++){if(c) coef*=5;if(coef>mmax) break;t3=coef;for(int d=0;d<19;d++){if(d) coef*=7;if(coef>mmax) break;if(a>=t[0][0] && b>=t[0][1] && c>=t[0][2] && d>=t[0][3]&& a>=t[1][0] && b>=t[1][1] && c>=t[1][2] && d>=t[1][3])times(g[a-t[0][0]][b-t[0][1]][c-t[0][2]][d-t[0][3]],h[a-t[1][0]][b-t[1][1]][c-t[1][2]][d-t[1][3]]); 	 }coef=t3;}coef=t2;}coef=t1;}
}void calc(){ci[0]=1;for(int i=1;i<=n;i++) ci[i]=ci[i-1]*9;c[0]=1;for(int i=1;i<=n;i++) c[i]=c[i-1]*10;C[0][0]=1;for(int i=1;i<=n;i++){C[i][0]=C[i][i]=1;for(int j=1;j<i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j];}long long t1=0,t2=0;if(f1==0) t1=c[tot1];else for(int i=1;i<=tot1;i++) t1+=C[tot1][i]*ci[tot1-i];if(f2==0) t2=c[tot2];else for(int i=1;i<=tot2;i++) t2+=C[tot2][i]*ci[tot2-i];times(t1,t2);
}int main(){scanf("%d",&n);scanf("%s",s+1);f1=f2=1;for(int i=1;i<=n;i++) if(s[i]=='?') tot1++;else f1*=s[i]-'0';for(int i=n+1;i<=2*n;i++) if(s[i]=='?') tot2++;else f2*=s[i]-'0';for(int i=1;i<=n;i++) mmax*=9;for(int i=1;i<=9;i++){int temp=i;while(temp%2==0) temp/=2,p[i][0]++;while(temp%3==0) temp/=3,p[i][1]++;while(temp%5==0) temp/=5,p[i][2]++;while(temp%7==0) temp/=7,p[i][3]++;}if(f1 && f2){prepare();solve();}calc();if(ans1) printf("%lld%lld",ans1,ans2);else printf("%lld",ans2);
}

      第三题:[NOI2006]网络收费

      题面太长。可以想到把一个配对的收益拆成两个点分别的收益之和。

      那么如果我们知道了这个点到根这条链的状态,我们就可以知道这个点分别取0/1的贡献,直接暴力枚举!

      用f[i][j]记录这个点所管辖的叶子结点取j个B的方案数。dfs时先钦定这个点一个状态,然后再向下dfs,那么到叶子结点的时候就知道一条链的状态,然后就可以得到当前叶子结点分别取0/1的收益,然后向上的时候直接合并就可以了。

      比赛时想到了这个状态,也想到了把收益拆开。但是没有想到怎么转移。我还是太菜了,这种题还是第一次见。

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#define ls (x<<1)
#define rs (x<<1|1)
using namespace std;int n,m;
int d[1025][11];
int type[1025],c[1025][2],ch[11];
int f[2048][1025];void dfs(int x,int l,int r,int dep){if(dep==n){f[x][0]=c[x-m+1][0];f[x][1]=c[x-m+1][1];for(int i=0;i<n;i++) f[x][ch[i]^1]+=d[x-m+1][i];return ;}int mid=(l+r)/2,mm=(r-l+1)/2;ch[dep]=0;dfs(ls,l,mid,dep+1);dfs(rs,mid+1,r,dep+1);for(int i=0;i<=mm;i++) {f[x][i]=2e9;for(int j=0;j<=i;j++)f[x][i]=min(f[x][i],f[ls][j]+f[rs][i-j]);}ch[dep]=1;dfs(ls,l,mid,dep+1);dfs(rs,mid+1,r,dep+1);for(int i=mm+1;i<=r-l+1;i++){f[x][i]=2e9;for(int j=max(i-mm,0);j<=mm;j++)f[x][i]=min(f[x][i],f[ls][j]+f[rs][i-j]);}
}int LCA(int x,int y){int t=n;while((x>>t) == (y>>t)) t--;return n-t-1;
}int main(){scanf("%d",&n);m=1<<n;for(int i=1;i<=m;i++) scanf("%d",&type[i]);for(int i=1;i<=m;i++) c[i][type[i]]=0,scanf("%d",&c[i][type[i]^1]);int x;for(int i=1;i<=m;i++) for(int j=i+1;j<=m;j++){scanf("%d",&x);	int lca=LCA(i+m-1,j+m-1);d[i][lca]+=x;d[j][lca]+=x;}dfs(1,1,m,0);int ans=2e9;for(int i=0;i<=m;i++) ans=min(ans,f[1][i]);printf("%d\n",ans);
}

这篇关于首师大附中集训第六天专题测试的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/313213

相关文章

如何测试计算机的内存是否存在问题? 判断电脑内存故障的多种方法

《如何测试计算机的内存是否存在问题?判断电脑内存故障的多种方法》内存是电脑中非常重要的组件之一,如果内存出现故障,可能会导致电脑出现各种问题,如蓝屏、死机、程序崩溃等,如何判断内存是否出现故障呢?下... 如果你的电脑是崩溃、冻结还是不稳定,那么它的内存可能有问题。要进行检查,你可以使用Windows 11

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

字节面试 | 如何测试RocketMQ、RocketMQ?

字节面试:RocketMQ是怎么测试的呢? 答: 首先保证消息的消费正确、设计逆向用例,在验证消息内容为空等情况时的消费正确性; 推送大批量MQ,通过Admin控制台查看MQ消费的情况,是否出现消费假死、TPS是否正常等等问题。(上述都是临场发挥,但是RocketMQ真正的测试点,还真的需要探讨) 01 先了解RocketMQ 作为测试也是要简单了解RocketMQ。简单来说,就是一个分

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

【测试】输入正确用户名和密码,点击登录没有响应的可能性原因

目录 一、前端问题 1. 界面交互问题 2. 输入数据校验问题 二、网络问题 1. 网络连接中断 2. 代理设置问题 三、后端问题 1. 服务器故障 2. 数据库问题 3. 权限问题: 四、其他问题 1. 缓存问题 2. 第三方服务问题 3. 配置问题 一、前端问题 1. 界面交互问题 登录按钮的点击事件未正确绑定,导致点击后无法触发登录操作。 页面可能存在

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

Java基础回顾系列-第六天-Java集合

Java基础回顾系列-第六天-Java集合 集合概述数组的弊端集合框架的优点Java集合关系图集合框架体系图java.util.Collection接口 List集合java.util.List接口java.util.ArrayListjava.util.LinkedListjava.util.Vector Set集合java.util.Set接口java.util.HashSetjava

Verybot之OpenCV应用一:安装与图像采集测试

在Verybot上安装OpenCV是很简单的,只需要执行:         sudo apt-get update         sudo apt-get install libopencv-dev         sudo apt-get install python-opencv         下面就对安装好的OpenCV进行一下测试,编写一个通过USB摄像头采

专题二_滑动窗口_算法专题详细总结

目录 滑动窗口,引入: 滑动窗口,本质:就是同向双指针; 1.⻓度最⼩的⼦数组(medium) 1.解析:给我们一个数组nums,要我们找出最小子数组的和==target,首先想到的就是暴力解法 1)暴力: 2)优化,滑动窗口: 1.进窗口 2.出窗口 3.更新值 2.⽆重复字符的最⻓⼦串(medium) 1)仍然是暴力解法: 2)优化: 进窗口:hash[s[rig