赞
踩
首先我们来看一下这样一个问题
有形如: a x 3 + b x 2 + c x + d = 0 a x^3 + b x^2 + c x + d = 0 ax3+bx2+cx+d=0 这样的一个一元三次方程。给出该方程中各项的系数( a , b , c , d a,b,c,d a,b,c,d 均为实数),并约定该方程存在三个不同实根(根的范围在 − 100 -100 −100 至 100 100 100 之间),且根与根之差的绝对值 ≥ 1 \ge 1 ≥1。要求由小到大依次在同一行输出这三个实根(根与根之间留有空格),并精确到小数点后 2 2 2 位。
提示:记方程 f ( x ) = 0 f(x) = 0 f(x)=0,若存在 2 2 2 个数 x 1 x_1 x1 和 x 2 x_2 x2,且 x 1 < x 2 x_1 < x_2 x1<x2, f ( x 1 ) × f ( x 2 ) < 0 f(x_1) \times f(x_2) < 0 f(x1)×f(x2)<0,则在 ( x 1 , x 2 ) (x_1, x_2) (x1,x2) 之间一定有一个根。
一行, 4 4 4 个实数 a , b , c , d a, b, c, d a,b,c,d。
一行, 3 3 3 个实根,从小到大输出,并精确到小数点后 2 2 2 位。
1 -5 -4 20
-2.00 2.00 5.00
【题目来源】
NOIP 2001 提高组第一题
这道题的数据范围相当之小,用暴力就能过
#include<bits/stdc++.h> #define ll long long #define ull unsigned long long using namespace std; double a,b,c,d; inline void check(double i){ double j=i+0.001; double y1=a*i*i*i+b*i*i+c*i+d; double y2=a*j*j*j+b*j*j+c*j+d; if(y1>=0&&y2<=0||y1<=0&&y2>=0) printf("%.2lf ",(i+j)/2); } int main() { scanf("%lf%lf%lf%lf",&a,&b,&c,&d); for(double i=-100;i<=100;i+=0.001)check(i); return 0; }
如果这道题的解空间再开打一下,开到1000,10000,那么暴力就一定过不去了
这时候就需要我们的二分法闪亮登场了
二分在下之前写过一篇博客讲解
二分解决的问题都有一个共同的性质:单调性
而如果某个问题的解空间是单峰的,不管是向外凸还是向内凹,都可以用另一种算法解决,三分
顾名思义,三分就是一种把解空间分成三段的算法,答案一定在某个段内,时间是 l o g 3 ( n ) log_3(n) log3(n)但也是 O ( l o g ( n ) ) O(log(n)) O(log(n))的算法
简单来说,二分解决零点问题,三分解决极值问题
Farmer John 建造了一个有 N N N( 2 ≤ N ≤ 1 0 5 2 \leq N \leq 10 ^ 5 2≤N≤105) 个隔间的牛棚,这些隔间分布在一条直线上,坐标是 x 1 , x 2 , ⋯ , x N x _ 1, x _ 2, \cdots, x _ N x1,x2,⋯,xN( 0 ≤ x i ≤ 1 0 9 0 \leq x _ i \leq 10 ^ 9 0≤xi≤109)。
他的 C C C( 2 ≤ C ≤ N 2 \leq C \leq N 2≤C≤N)头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,Farmer John 想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?
第 1 1 1 行:两个用空格隔开的数字 N N N 和 C C C。
第 2 ∼ N + 1 2 \sim N+1 2∼N+1 行:每行一个整数,表示每个隔间的坐标。
输出只有一行,即相邻两头牛最大的最近距离。
5 3
1
2
8
4
9
3
二分每一种可能的间隔长度,检查是否符合条件
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long long ll; const int N=100005; int n,m,x[N]; template<typename T> inline void read(T &x) { x=0;char c = getchar();int s = 1; while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();} x*=s; } template<typename T> inline void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return; } inline bool check(int d){ int cow=1; int rgt=x[1]+d; for(int i=2;i<=n;i++){ if(x[i]<rgt)continue; ++cow; rgt=x[i]+d; } return cow>=m; } int main(){ read(n),read(m); for(int i=1;i<=n;i++)read(x[i]); sort(x+1,x+n+1); int l=0,r=x[n]-x[1]; while(l<=r){ int mid=(l+r)>>1; if(check(mid))l=mid+1; else r=mid-1; } write(r); printf("\n"); return 0; }
给一个长度为 n n n 的数列,我们需要找出该数列的一个子串,使得子串平均数最大化,并且子串长度 ≥ m \ge m ≥m。
第一行两个整数 n n n 和 m m m。
接下来 n n n 行,每行一个整数 a i a_i ai,表示序列第 i i i 个数字。
一个整数,表示最大平均数的 1000 1000 1000 倍,如果末尾有小数,直接舍去,不要用四舍五入求整。
10 6
6
4
2
10
3
8
5
9
4
1
6500
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const double eps=1e-10; template<typename T> inline void read(T &x) { x=0;char c = getchar();int s = 1; while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();} x*=s; } template<typename T> inline void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return; } int n,len,a[100010]; double b[100010],sum[100010]; int main(){ read(n),read(len); for(int i=1;i<=n;i++)read(a[i]); double l=-1e6,r=1e6,mid; while(r-l>eps){ mid=(l+r)/2; for(int i=1;i<=n;i++){ b[i]=a[i]-mid; sum[i]=sum[i-1]+b[i]; } double minn=1e9,tmp=-1e9; for(int i=len;i<=n;i++){ minn=min(minn,sum[i-len]); tmp=max(tmp,sum[i]-minn); } if(tmp>-eps)l=mid; else r=mid; } cout<<(int)((r+eps)*1000)<<endl; return 0; }
在某个课程中,你需要进行 n n n 次测试。
如果你在共计 b i b_i bi 道题的测试 i i i 上的答对题目数量为 a i a_i ai,你的累积平均成绩就被定义为
100 × ∑ i = 1 n a i ∑ i = 1 n b i 100\times \dfrac{\displaystyle \sum_{i=1}^n a_i}{\displaystyle \sum_{i=1}^n b_i} 100×i=1∑nbii=1∑nai
给定您的考试成绩和一个正整数 k k k,如果您被允许放弃任何 k k k 门考试成绩,您的累积平均成绩的可能最大值是多少。
假设您进行了 3 3 3 次测试,成绩分别为 5 / 5 , 0 / 1 5/5,0/1 5/5,0/1 和 2 / 6 2/6 2/6。
在不放弃任何测试成绩的情况下,您的累积平均成绩是
100 × 5 + 0 + 2 5 + 1 + 6 = 50 100\times \frac{5+0+2}{5+1+6}=50 100×5+1+65+0+2=50
然而,如果你放弃第三门成绩,则您的累积平均成绩就变成了
100 × 5 + 0 5 + 1 ≈ 83.33 ≈ 83 100\times \frac{5+0}{5+1}\approx 83.33\approx 83 100×5+15+0≈83.33≈83
输入包含多组测试用例,每个测试用例包含三行。
对于每组测试用例,第一行包含两个整数 n n n 和 k k k。
第二行包含 n n n 个整数,表示所有的 a i a_i ai。
第三行包含 n n n 个整数,表示所有的 b i b_i bi。
当输入用例 n = k = 0 n=k=0 n=k=0 时,表示输入终止,且该用例无需处理。
对于每个测试用例,输出一行结果,表示在放弃 k k k 门成绩的情况下,可能的累积平均成绩最大值。
结果应四舍五入到最接近的整数。
3 1
5 0 2
5 1 6
4 2
1 2 7 9
5 6 7 9
0 0
83
100
数据范围 1 ≤ n ≤ 1000 1 \le n \le 1000 1≤n≤1000, 0 ≤ k < n 0 \le k < n 0≤k<n, 0 ≤ a i ≤ b i ≤ 1 0 9 0 \le a_i \le b_i \le 10^9 0≤ai≤bi≤109。
#include<iostream> #include<cmath> #include<algorithm> #include<cstdio> using namespace std; const double eps=1e-8; int n,k; double a[1010],b[1010],tmp[1010]; inline bool check(double m){ double cnt=0; for(int i=1;i<=n;i++){ tmp[i]=a[i]-b[i]*m; } sort(tmp+1,tmp+1+n); for(int i=n;i>k;i--){ cnt+=tmp[i]; } return cnt>=0; } int main(){ while(scanf("%d%d",&n,&k)){ if(n==0&&k==0)break; for(int i=1;i<=n;i++)scanf("%lf",&a[i]); for(int i=1;i<=n;i++)scanf("%lf",&b[i]); double st=0,ed=100; while(fabs(ed-st)>=eps){ double mid=st+(ed-st)/2; if(check(mid))st=mid; else ed=mid; } st*=100.0; printf("%.0lf\n",st); } return 0; }
给定 n n n 个二次函数 f 1 ( x ) , f 2 ( x ) , … , f n ( x ) f_1(x),f_2(x),\dots,f_n(x) f1(x),f2(x),…,fn(x)(均形如 a x 2 + b x + c ax^2+bx+c ax2+bx+c),设 F ( x ) = max { f 1 ( x ) , f 2 ( x ) , . . . , f n ( x ) } F(x)=\max\{f_1(x),f_2(x),...,f_n(x)\} F(x)=max{f1(x),f2(x),...,fn(x)},求 F ( x ) F(x) F(x) 在区间 [ 0 , 1000 ] [0,1000] [0,1000] 上的最小值。
输入第一行为正整数 T T T,表示有 T T T 组数据。
每组数据第一行一个正整数 n n n,接着 n n n 行,每行 3 3 3 个整数 a , b , c a,b,c a,b,c,用来表示每个二次函数的 3 3 3 个系数,注意二次函数有可能退化成一次。
每组数据输出一行,表示 F ( x ) F(x) F(x) 的在区间 [ 0 , 1000 ] [0,1000] [0,1000] 上的最小值。答案精确到小数点后四位,四舍五入。
2
1
2 0 0
2
2 0 0
2 -4 2
0.0000
0.5000
对于 50 % 50\% 50% 的数据, n ≤ 100 n\le 100 n≤100。
对于 100 % 100\% 100% 的数据, T < 10 T<10 T<10, n ≤ 1 0 4 \ n\le 10^4 n≤104, 0 ≤ a ≤ 100 0\le a\le 100 0≤a≤100, ∣ b ∣ ≤ 5 × 1 0 3 |b| \le 5\times 10^3 ∣b∣≤5×103, ∣ c ∣ ≤ 5 × 1 0 3 |c| \le 5\times 10^3 ∣c∣≤5×103。
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> #define eps 1e-10 using namespace std; int n,t; struct f{ int a,b,c; }s[10005]; template<typename T> inline void read(T &x) { x=0;char c = getchar();int s = 1; while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();} x*=s; } template<typename T> inline void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return; } inline double calc(double num){ double maxn=-1e9; for(int i=1;i<=n;i++){ maxn=max(maxn,s[i].a*num*num+s[i].b*num+s[i].c); } return maxn; } int main(){ read(t); while(t--){ read(n); for(int i=1;i<=n;i++){ read(s[i].a); read(s[i].b); read(s[i].c); } double l=0,r=1000,midl,midr; while(r-l>eps){ midl=l+(r-l)/3,midr=r-(r-l)/3; if(calc(midl)>calc(midr))l=midl; else r=midr; } printf("%.4lf\n",calc(l)); } return 0; }
哆来咪·苏伊特参加了 n n n 场比赛。 比赛 i i i 只能在第 i i i 天进行。比赛 i i i 的难度为 a i a_i ai。最初,哆来咪的 IQ 为 q q q 。 在第 i i i 天,哆来咪将选择是否参加比赛 i。只有当她当前的 IQ 大于 0 0 0 时,她才能参加比赛。
如果哆来咪选择在第 i i i 天参加比赛 i i i,则会发生以下情况:
如果她选择不参加比赛,一切都不会改变。哆来咪想参加尽可能多的比赛。请给哆来咪一个解决方案。
第一行包含一个正整数 t t t ( 1 ≤ t ≤ 1 0 4 1\le t\le10^4 1≤t≤104) ,表示测试数据的组数。
第二行包含两个整数 n n n 和 q q q ( 1 ≤ n ≤ 1 0 5 1\le n\le10^5 1≤n≤105, 1 ≤ q ≤ 1 0 9 1\le q\le10^9 1≤q≤109),表示比赛次数和哆来咪最开始时的 IQ。
第三行包含 n n n 个整数 a 1 , a 2 ⋯ a n a_1,a_2⋯a_n a1,a2⋯an( 1 ≤ a i ≤ 1 0 9 1\le a_i≤10^9 1≤ai≤109),表示每场比赛的难度。
数据保证 n n n 之和不超过 1 0 5 10^5 105。
对于每组数据,输出一个二进制字符串 s s s,如果哆来咪应该选择参加比赛 i i i,则 s i = 1 s_i=1 si=1,否则 s i = 0 s_i=0 si=0。 字符串中 1 1 1 的数量应该尽可能的多,并且当她的 IQ 为 0 0 0 或更低时,她不应该参加比赛。
如果有多个解决方案,你可以输出任意一个。
在第一个测试用例中,哆来咪参加了唯一的比赛。她的 IQ 没有下降。
在第二个测试用例中,哆来咪参加了两个比赛。在参加比赛 2 2 2 后,她的 IQ 下降了 1 1 1。
在第三个测试用例中,哆来咪参加了比赛 1 1 1 和比赛 2 2 2。她的 IQ 在参加比赛 2 2 2 后降至 0 0 0,因此她无法参加比赛 3 3 3。
Doremy is asked to test $ n $ contests. Contest $ i $ can only be tested on day $ i $ . The difficulty of contest $ i $ is $ a_i $ . Initially, Doremy’s IQ is $ q $ . On day $ i $ Doremy will choose whether to test contest $ i $ or not. She can only test a contest if her current IQ is strictly greater than $ 0 $ .
If Doremy chooses to test contest $ i $ on day $ i $ , the following happens:
If she chooses not to test a contest, nothing changes.Doremy wants to test as many contests as possible. Please give Doremy a solution.
The input consists of multiple test cases. The first line contains a single integer $ t $ ( $ 1\le t\le 10^4 $ ) — the number of test cases. The description of the test cases follows.
The first line contains two integers $ n $ and $ q $ ( $ 1 \le n \le 10^5 $ , $ 1 \le q \le 10^9 $ ) — the number of contests and Doremy’s IQ in the beginning.
The second line contains $ n $ integers $ a_1,a_2,\cdots,a_n $ ( $ 1 \le a_i \le 10^9 $ ) — the difficulty of each contest.
It is guaranteed that the sum of $ n $ over all test cases does not exceed $ 10^5 $ .
For each test case, you need to output a binary string $ s $ , where $ s_i=1 $ if Doremy should choose to test contest $ i $ , and $ s_i=0 $ otherwise. The number of ones in the string should be maximum possible, and she should never test a contest when her IQ is zero or less.
If there are multiple solutions, you may output any.
5
1 1
1
2 1
1 2
3 1
1 2 1
4 2
1 4 3 1
5 2
5 1 2 4 3
1
11
110
1110
01111
In the first test case, Doremy tests the only contest. Her IQ doesn’t decrease.
In the second test case, Doremy tests both contests. Her IQ decreases by $ 1 $ after testing contest $ 2 $ .
In the third test case, Doremy tests contest $ 1 $ and $ 2 $ . Her IQ decreases to $ 0 $ after testing contest $ 2 $ , so she can’t test contest $ 3 $ .
#include<cstdio> #include<cstring> using namespace std; #define N 100000 int t,n,q,a[N+2],pos; bool ans[N+2]; inline bool check(int x){ int w=q; for(int i=x+1;i<=n;++i){ if(a[i]>w)--w; } return w>=0; } int main(){ scanf("%d",&t); while(t--){ scanf("%d%d",&n,&q); for(int i=1;i<=n;++i)scanf("%d",a+i); for(int l=0,r=n,mid;l<=r;){ mid=(l+r)>>1; if(check(mid)){ pos=mid; r=mid-1; } else l=mid+1; } for(int i=1;i<=pos;++i){ if(a[i]<=q)ans[i]=true; else ans[i]=false; } for(int i=pos+1;i<=n;++i)ans[i]=true; for(int i=1;i<=n;++i)printf("%d",ans[i]); printf("\n"); } return 0; }
给定一个长为 n n n 的序列 a a a。
定义一个 n n n 个点的无向完全图,点 l l l 和点 r r r 之间的距离为 min i ∈ [ l , r ] { a i } \min\limits_{i\in[l,r]}\{a_i\} i∈[l,r]min{ai}。
你可以进行 k k k 次操作,每次操作可以选定 ∀ i ∈ [ 1 , n ] \forall i \in [1,n] ∀i∈[1,n] 并将 a i a_i ai 赋值为一个 [ 1 , 1 0 9 ] [1,10^9] [1,109] 的整数。请最大化这个图的直径。
设 d ( u , v ) d(u,v) d(u,v) 表示 u u u 到 v v v 的最短路径长度,图的直径定义为 max 1 ≤ u < v ≤ n d ( u , v ) \max\limits_{1\leq u < v \leq n} d(u,v) 1≤u<v≤nmaxd(u,v)。
输出最大化的直径长度。
— Do you have a wish?
— I want people to stop gifting each other arrays.
O_o and Another Young Boy
An array of $ n $ positive integers $ a_1,a_2,\ldots,a_n $ fell down on you from the skies, along with a positive integer $ k \le n $ .
You can apply the following operation at most $ k $ times:
Then build a complete undirected weighted graph with $ n $ vertices numbered with integers from $ 1 $ to $ n $ , where edge $ (l, r) $ ( $ 1 \le l < r \le n $ ) has weight $ \min(a_{l},a_{l+1},\ldots,a_{r}) $ .
You have to find the maximum possible diameter of the resulting graph after performing at most $ k $ operations.
The diameter of a graph is equal to $ \max\limits_{1 \le u < v \le n}{\operatorname{d}(u, v)} $ , where $ \operatorname{d}(u, v) $ is the length of the shortest path between vertex $ u $ and vertex $ v $ .
Each test contains multiple test cases. The first line contains the number of test cases $ t $ ( $ 1 \le t \le 10^4 $ ). Description of the test cases follows.
The first line of each test case contains two integers $ n $ and $ k $ ( $ 2 \le n \le 10^5 $ , $ 1 \le k \le n $ ).
The second line of each test case contains $ n $ positive integers $ a_1,a_2,\ldots,a_n $ ( $ 1 \le a_i \le 10^9 $ ).
It is guaranteed that the sum of $ n $ over all test cases does not exceed $ 10^5 $ .
For each test case print one integer — the maximum possible diameter of the graph after performing at most $ k $ operations.
6
3 1
2 4 1
3 2
1 9 84
3 1
10 2 6
3 2
179 17 1000000000
2 1
5 9
2 2
4 2
4
168
10
1000000000
9
1000000000
In the first test case, one of the optimal arrays is $ [2,4,5] $ .
The graph built on this array:
$ \operatorname{d}(1, 2) = \operatorname{d}(1, 3) = 2 $ and $ \operatorname{d}(2, 3) = 4 $ , so the diameter is equal to $ \max(2,2,4) = 4 $ .
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const int N=100010; typedef long long ll ; ll t,n,k,a[N],pre[N],sub[N]; template<typename T> inline void read(T &x) { x=0;char c = getchar();ll s = 1; while(c < '0' || c > '9') {if(c == '-') s = -1;c = getchar();} while(c >= '0' && c <= '9') {x = x*10 + c -'0';c = getchar();} x*=s; } template<typename T> inline void write(T x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); return; } inline bool check(ll pos){ for(ll i=1;i<=n;i++) pre[i]=pre[i-1]+(ll)((a[i]<<1)<pos); for(ll i=n;i;i--) sub[i]=sub[i+1]+(ll)((a[i]<<1)<pos); ll minx=0x3f3f3f3f; for(ll i=1;i<n;i++) minx=min(minx,pre[i-1]+sub[i+2]+(ll)(a[i] < pos) + (ll)(a[i + 1] < pos)); return minx<=k; } int main(){ read(t); while (t--) { read(n),read(k); memset(pre, 0, sizeof(pre)); memset(sub, 0, sizeof(sub)); for (ll i = 1; i <= n; i++) read(a[i]); ll l = 0, r = 1e9, ans = 0; while (l <= r) { ll mid = l + r >> 1; if (check(mid)) { l=mid+1; ans=mid; } else r = mid-1; } write(ans); printf("\n"); } return 0; }
这是我的第十二篇文章,如有纰漏也请各位大佬指正
辛苦创作不易,还望看官点赞收藏打赏,后续还会更新新的内容。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。