先写这几道题,比赛的时候有事就只签了个到。
E. Excellent Engineers
这个题的意思就是如果一个人的r1,r2,r3中的某一个比已存在的人中的小,就把这个人添加到名单中。
因为是3个变量,所以按其中一个变量进行sort排序,然后,剩下的两个变量,一个当位置pos,一个当值val,通过线段树的单点更新和区间最值操作,就可以把名单确定。
代码:
1 //E-线段树 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<algorithm> 7 #include<cstdlib> 8 #include<queue> 9 #include<stack> 10 using namespace std; 11 typedef long long ll; 12 const int inf=0x3f3f3f3f; 13 const double eps=1e-5; 14 const int maxn=1e5+10; 15 #define lson l,m,rt<<1 16 #define rson m+1,r,rt<<1|1 17 struct node 18 { 19 int x,y,z; 20 bool operator<(const node&a)const 21 { 22 return x<a.x; 23 } 24 }a[maxn]; 25 int tree[maxn<<2]; 26 27 void PushUp(int rt) 28 { 29 tree[rt]=min(tree[rt<<1],tree[rt<<1|1]); 30 } 31 32 void build(int l,int r,int rt) 33 { 34 if(l==r) 35 { 36 tree[rt]=inf; 37 return ; 38 } 39 int m=(l+r)>>1; 40 build(lson); 41 build(rson); 42 PushUp(rt); 43 } 44 //单点更新 45 void update(int pos,int val,int l,int r,int rt) 46 { 47 if(l==r) 48 { 49 tree[rt]=val; 50 return ; 51 } 52 int m=(l+r)>>1; 53 if(pos<=m)update(pos,val,lson); 54 else update(pos,val,rson); 55 PushUp(rt); 56 } 57 58 //区间最值 59 int query(int L,int R,int l,int r,int rt) 60 { 61 if(L<=l&&r<=R) 62 { 63 return tree[rt]; 64 } 65 int m=(l+r)>>1; 66 int ret=inf; 67 if(L<=m)ret=min(ret,query(L,R,lson)); 68 if(R> m)ret=min(ret,query(L,R,rson)); 69 return ret; 70 } 71 72 73 int main() 74 { 75 int t,n; 76 scanf("%d",&t); 77 while(t--) 78 { 79 scanf("%d",&n); 80 build(1,n,1); 81 for(int i=0;i<n;i++) 82 scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z); 83 sort(a,a+n); 84 int ans=0; 85 for(int i=0;i<n;i++) 86 { 87 if(a[i].y!=1) 88 { 89 int cnt=query(1,a[i].y-1,1,n,1); 90 if(cnt<a[i].z)continue; 91 } 92 ans++; 93 update(a[i].y,a[i].z,1,n,1); 94 } 95 printf("%d\n",ans); 96 } 97 return 0; 98 }
G. Growling Gears
此题为签到题,直接中学的数学知识点,一元二次方程的顶点公式(-b/2*a,(4*a*c-b*b)/4*a);直接就可以得到结果。
代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<cstdlib> 6 #include<queue> 7 #include<map> 8 #include<algorithm> 9 using namespace std; 10 typedef long long ll; 11 const int maxn=1e5+10; 12 int main(){ 13 int t;scanf("%d",&t); 14 while(t--){ 15 int n;scanf("%d",&n); 16 int a,b,c; 17 ll maxx=-1;int ans; 18 for(int i=1;i<=n;i++){ 19 scanf("%d%d%d",&a,&b,&c); 20 ll cnt=(4*a*c*(-1)-b*b)/(4*a*(-1)); 21 if(maxx<=cnt){ 22 maxx=cnt; 23 ans=i; 24 } 25 } 26 printf("%d\n",ans); 27 } 28 return 0; 29 }
I. Interesting Integers
应该是叫思维题吧,反正敲一下脑壳才知道自己哪里写错了。要敢于暴力。
这个题的题意就是给你一个数,让你逆推出递推的最开始的两个数(假设一开始的两个数为x和y),而且要求x<=y。
通过找规律可以发现,这个题就是求解a*x+b*y=k这个方程的x和y的值,并且要x和y为最小满足条件的解。可以找规律出一个公式fi[i]*x+(fi[i-1]+fi[i])*y=n。因为不知道n具体是在第几步推出来的,所以for循环跑一遍预处理出来的斐波那契数列(存到fi数组中),最多不超过50个数,否则会爆1e9。
因为是求解a*x+b*y=k这个方程的x和y的值,并且要x和y为最小满足条件的解,当时脑子一热就说,这不是扩展欧几里得吗,然后突然发现,斐波那契数列相邻两个数是互质的,他们的exgcd为1,并没有什么用,打扰了,所以还是老老实实去写暴力。
通过该方程,可以大体确定y的范围,y=1;y<=cnt+1,因为要求在满足a<=b的条件下的最小值,所以斐波那契数列中的数作为两个数的系数,只有系数尽可能大,这两个数才会尽可能小,所以斐波那契数列的遍历从大到小遍历,因为要求y尽量小的前提下x小且x<=y,所以从小到大遍历y,找到第一个满足条件:x<=y的就是结果。如果都是从大到小或者从小到大遍历或者怎么遍历,会超时,所以找到结果直接输出就可以了。
自己写的时候,2和4的结果输不出来,然后特判2和4水过去了,仔细想了一下,发现是斐波那契数列初始值设错了,把0给忘了,然后改了之后就过了。简直是智障,智障写了好久的智障题。。。
代码:
1 //I-斐波那契数列打表 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #include<cmath> 6 #include<cstdlib> 7 #include<queue> 8 #include<map> 9 #include<algorithm> 10 using namespace std; 11 typedef long long ll; 12 const int maxn=1e5+10; 13 const int inf=0x3f3f3f3f; 14 int fi[50]; 15 void fibonacci() 16 { 17 fi[0]=0,fi[1]=1;fi[2]=1; 18 for(int i=3;i<=45;i++) 19 fi[i]=fi[i-1]+fi[i-2]; 20 } 21 int main() 22 { 23 int t,n; 24 fibonacci(); 25 scanf("%d",&t); 26 while(t--) 27 { 28 scanf("%d",&n); 29 { 30 int flag=0; 31 for(int i=45;i>=0;i--) 32 { 33 int a=fi[i],b=fi[i-1]+fi[i]; 34 int cnt=n/a; 35 for(int y=1;y<=cnt+1;y++) 36 { 37 if((n-b*y)%a==0&&(n-b*y)>0) 38 { 39 int x=(n-b*y)/a; 40 if(x<=y&&x!=0) 41 { 42 flag=1; 43 printf("%d %d\n",x,y); 44 break; 45 } 46 } 47 if(flag==1)break; 48 } 49 if(flag==1)break; 50 } 51 } 52 } 53 return 0; 54 }
感谢思力酱,嘲笑我的智障行为并且锤了我的脑壳,让我机灵一下发现是初始值设错了,思力酱是真的严格呢。
就先这样吧,其他题等补了再写题解。
原文地址:https://www.cnblogs.com/ZERO-/p/9297446.html