试题链接:http://www.accoders.com/contest.php?cid=1895 考试密码请私信;
特别鸣谢:zkc奆佬帮助我优化本篇题解(语言表达方面)
T1
显然二分求解的一道题,难度中等,但是会被疯狂卡精度
非常恶心,非常毒瘤
思路:输入时维护一个前缀和数组,然后分别从前,后方向遍历,找最大最小值
,同时记录L,R,二分x,check函数中另起一个数组算一下'-x'后的数组然后,还是
从前后遍历,找最大最小值,记录l,r,最后判断L和R的大小是不是也符合l,r的大小
(就是L<R&&l<r||L>R&&l>r),然后疯狂卡精度即可

1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[200010]; 4 double b[200010]; 5 double c[200010]; 6 double maxx,ans,tans,x,num; 7 int n,L,R=n+1,bigg=-99999,small=10000; 8 inline bool check(double x){ 9 double maxx=-99999,minn=10000;int l=0,r=n+1; 10 for(register int i=1;i<=n;i++){ 11 if(L<R) c[i]=b[i]-x*(i*1.0); 12 else c[i]=b[i]+x*(i*1.0); 13 } 14 for(register int i=n;i>=0;i--) if(maxx<c[i]) maxx=c[i],r=i; 15 for(register int i=1;i<=n;i++) if(minn>c[i]) minn=c[i],l=i; 16 ans=maxx-minn; 17 if((l<r&&L<R)||(l>r&&L>R)) return true; 18 else return false; 19 } 20 double ef(double l,double r){ 21 double mid=(l+r)/(2.0); 22 if(r-l<0.00000000001) return mid; 23 if(check(mid)) return ef(mid,r); 24 else return ef(l,mid); 25 } 26 int main(){ 27 scanf("%d",&n); 28 for(register int i=1;i<=n;i++){scanf("%d",&a[i]);b[i]=b[i-1]+a[i];} 29 for(register int i=n;i>=0;i--) if(bigg<b[i]) bigg=b[i],R=i; 30 for(register int i=1;i<=n;i++) if(small>b[i]) small=b[i],L=i; 31 double qwq=ef(0,20000); 32 check(qwq); 33 if(ans>499&&ans<500) ans-=0.000001; 34 printf("%.6lf",ans); 35 return 0; 36 }
T2
显然的宽搜啊~~~ boom 时间超限,但其实难度中等偏下
所以是二分宽搜/二分深搜....(这谁想得到啊!!!!)QAQ
还有一点我用的是宽搜 742ms,而zkc奆佬用的是深搜 255ms QAQ!
思路:二分找到最小的伤害值,每次二分一个最大的伤害值搜索跑图,高于伤害值的点都不去走
若能走到最后一排则符合二分向下,否则二分向上,最后找到的就是最小的最大伤害值

1 #include <bits/stdc++.h> 2 using namespace std; 3 int a[1010][1010]; 4 int fx[4]={1,0,-1,0},fy[4]={0,1,0,-1}; 5 int x,y,ans,n,m,maxx; 6 queue <int> q; 7 bool vis[1010][1010]; 8 bool check(int qwq){ 9 while(!q.empty()) q.pop(); 10 for(register int i=1;i<=m;i++)q.push(1),q.push(i),vis[1][i]=1; 11 while(!q.empty()){ 12 x=q.front();q.pop(); 13 y=q.front();q.pop(); 14 if(x==n) return true; 15 for(register int i=0;i<4;i++){ 16 int px=x+fx[i]; 17 int py=y+fy[i]; 18 if(px<1||px>n||py<1||py>m||a[px][py]>qwq||vis[px][py]) continue; 19 q.push(px); 20 q.push(py); 21 vis[px][py]=1; 22 } 23 } 24 return false; 25 } 26 int ef(int l,int r){ 27 //cout<<l<<" "<<r<<endl; 28 if(l==r) return l; 29 int mid=(l+r)>>1; 30 memset(vis,false,sizeof(vis)); 31 if(check(mid)) ef(l,mid); 32 else ef(mid+1,r); 33 } 34 int main(){ 35 scanf("%d%d",&n,&m); 36 for(register int i=1;i<=n;i++) 37 for(register int j=1;j<=m;j++){scanf("%d",&a[i][j]);maxx=max(maxx,a[i][j]);} 38 printf("%d",ef(0,1000)); 39 return 0; 40 }
T3
显然打表啊!打表出奇迹!打表nb!难度中等
打表时间复杂度O(285年) 算了吧....
思路:其实这题跟数论也有点关系,首先先打个素数表,众所周知,素数*素数的得数必然有两个约数
前提是两个素数不等,假设是两个相同素数相乘每乘一次显然约数个数=(i+1)
举例:
2 约数=2
2*2 约数=3
2*2*2 约数=4
那搜索方式就是从最大的素数往下搜索,如果乘上当前素数没爆,接着乘
爆了就往回走,无路可走时显然就结束了

1 #include <bits/stdc++.h> 2 using namespace std; 3 int p[26]={1,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,101}; 4 int primenum; 5 bool ac; 6 long long ans,tans; 7 long long n; 8 void dfs(long long now,long long num,long long deep,long long last){ 9 if(deep>=26) return; 10 else{ 11 if(num>ans){tans=now,ans=num;} 12 else if(num==ans) tans=min(tans,now); 13 for(register int i=1;i<=last;i++){ 14 if(now*p[deep]<=n){ 15 now*=p[deep]; 16 dfs(now,num*(i+1),deep+1,i); 17 } 18 else break; 19 } 20 } 21 } 22 int main(){ 23 scanf("%lld",&n); 24 dfs(1,1,0,26); 25 printf("%lld",tans); 26 return 0; 27 }
end;