MZOJ 2018-03-31 考试随想

第一道题,先是题看错了,贪心的时候没有贪心对,改了1mol,最后才改对,预计正常用时20min。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 const int maxn=10000+10;
 9 const long long mods=1000000009;
10 
11 int n;
12 long long t=0;
13 long long ans=0;
14 
15 struct node{
16     int x,y;
17 }peo[maxn];
18 
19 bool cmp(node a,node b)
20 {
21     return a.x*b.y < a.y*b.x; 
22 }
23 
24 void readdate()
25 {
26     int ai,bi;
27     scanf("%d",&n);
28     for(int i=1;i<=n;i++)
29     {
30         scanf("%d%d",&ai,&bi);
31         peo[i].x=ai;
32         peo[i].y=bi;
33     }
34     sort(peo+1,peo+1+n,cmp);
35     return ;
36 }
37 
38 void work()
39 {
40     for(int i=1;i<=n;i++)
41     {
42         ans=((ans+peo[i].x+peo[i].y*ans)+mods)%mods;
43     }
44     cout<<ans<<endl;
45 }
46 
47 int main()
48 {
49     readdate();
50     work();
51     return 0;
52 }

 

 




 

第二道题也十分简单,不就是一个普通的加减值问题吗?

但是,我首先想到的是用公式

 设g1为大于答案值的个数,g2是小于答案值的个数,s1是大于答案的每个数的总和,s2是小于答案的每个数的总和。同时,答案为x,能量损失为a。

 则有:(s1-h1*x)*a = h2*x - s2

 样例过了,但是好像有精度上的问题。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 const int maxn=10000+10;
 9 
10 int n,k;
11 int shu[maxn];
12 int sum;
13 int sum1,sum2;
14 int g1,g2;
15 double pin,ans;
16 
17 void readdate()
18 {
19     cin>>n>>k;
20     for(int i=1;i<=n;i++)
21     {
22         scanf("%d",&shu[i]);
23         sum+=shu[i];
24     }
25     sort(shu+1,shu+n+1);
26     pin = (sum*1.0) / (n*1.0);  //我们可以轻易证得,答案 < 所有数加起来的平均数,(因为有能量损失)
27     for(int i=1;i<=n;i++)
28     {
29         if(shu[i]-pin>=0)
30         {
31             sum1+=shu[i];
32             g1++;
33         }
34         else
35         {
36             sum2+=shu[i];
37             g2++;
38         }
39     }
40     return ;
41 }
42 
43 void work()
44 {
45     double a=(100-k)*0.01;
46     ans=(a*sum1 + sum2*1.0)/(g2*1.0 + g1*a);
47     printf("%.9lf\n",ans);
48 }
49 
50 int main()
51 {
52     readdate();
53     work();
54     return 0;
55 }

 

 

 

其次,我才想到了二分答案。

首先读入每个数,在读的时候要特判,如果读进去的数都是一样的,或者n==1,即只有一个值,那我们就可以直接输出了。

然后读完了所有数后,要进行sort排序,我是按照从大到小排序的,讲二分的 l 设为数列里最小的,r 设为最大的。因为是double型,有精度问题,所以while循环的条件就是(r-l)> 10-12 ,然后就是常规取mid了。这个地方,check的条件也是十分明显的。首先把所有大于mid的数加起来(因为精度问题,也需要用(a-mid)> 10-12 来判断大小),然后每次一个比它小的数,就从sum中减去,如果不够了,就说明我们枚举的ans大了,这时候就r=mid,否则这个方案就是可行的,l=mid(同时我习惯于在这一步就把答案更新为l)。

 

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 const int maxn=10000+10;
 9 
10 int n,k;
11 double shu[maxn];
12 double l,r,mid;
13 double ans;
14 bool flag;
15 
16 bool cmp(double x,double y)
17 {
18     return x>y;
19 }
20 
21 void readdate()
22 {
23     cin>>n>>k;
24     for(int i=1;i<=n;i++)
25     {
26         scanf("%lf",&shu[i]);
27         if(shu[i] != shu[i-1])
28             flag=true;
29     }
30     if(!flag || n==1)  //特判
31     {
32         printf("%.9f\n",shu[1]);
33         exit(0);
34     }
35     sort(shu+1,shu+1+n,cmp);
36     l=shu[n];
37     r=shu[1];
38 }
39 
40 bool check(double now)
41 {
42     double sum1=0,sum2=0;
43     for(int i=1;i<=n;i++)
44     {
45         if(shu[i]-now>=1e-12)
46         {
47             sum1+=(shu[i]-now);
48         }
49         else
50         {
51             double jian=(now-shu[i])*100.0 / (100.0 - k);  //因为有能量损失,所以减掉需要的能量时,要除以能量损失百分比。为了精度,我上下同时乘以了一个100.
52             if(jian-sum1>1e-12)
53             {
54                 return false;
55             }
56             else
57             {
58                 sum1-=jian;
59             }
60         }
61     }
62     return true;
63 }
64 
65 void work()
66 {
67     while(r-l>1e-12)
68     {
69         mid=(r+l)/2.0;
70         if(check(mid))
71         {
72             ans=mid;
73             l=mid;
74         }
75         else
76         {
77             r=mid;
78         }
79     }
80     printf("%.9f\n",ans);
81 }
82 
83 int main()
84 {
85     readdate();
86     work();
87     return 0;
88 }

 

 

 




 

 

第三道题,很明显的一个最长上升子序列嘛。注意的条件不就是要判断两个相邻值之间项数差值是否大于d,以及注意数据范围,用nlogn的方法求最长上升子序列就可以了。我用的是之前在一道题解里看到过得求上升子序列的方法,正好有一个q的数组可以来判断d的关系。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 using namespace std;
 7 
 8 const int maxn=100000+10;
 9 
10 int n,d,tot;
11 int q[maxn];
12 int c[maxn];
13 int s[maxn];
14 
15 int main()
16 {
17     while(scanf("%d%d",&n,&d)!=EOF)
18     {
19         tot=0;
20         memset(c,0x3f3f3f,sizeof(c));  //初始化为极大值
21         for(int i=1;i<=n;i++)
22         {
23             scanf("%d",&s[i]);
24         }
25         for(int i=1;i<=n;i++)
26         {
27             q[i]=lower_bound(c+1,c+1+n,s[i])-c;   //找到第一个大于等于s[i]的数,q存的就是当前第i个数字所存的位置
28             if(q[i]>tot)
29                 tot=q[i];    //如果q[i]找到位置都大于答案了,就重新赋值答案tot
30             int cha=i-d;    //cha值表示当前这个点最近能够取得它之前的哪个点
31             if(cha>0 && c[q[cha]]>s[cha])    //如果cha>0,即表示i之前有可取的点。同时在答案序列c里,这个可取点所对应的位置的数要大于当前这个点的值,那么我们的重新赋值才有意义,可以为后来的点腾更多的空间
32                 c[q[cha]]=s[cha];    //重新赋值q[cha]所对应的数列c的值
33         }
34         cout<<tot<<endl;
35     }
36     return 0;
37 }

 

 

 

 




 

 

至于第四道题嘛,洛谷上的大佬都讲得很清楚了,一个状压dp。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 
 6 int floors[5200][15];
 7 int f[5200];
 8 int maps[15][15];
 9 int n,m,st,en,va;
10 int ans=0x3f3f3f;
11 
12 void clear()
13 {
14     memset(floors,0,sizeof(floors));
15     memset(f,0x3f3f,sizeof(f));
16 }
17 
18 void work(int k)
19 {
20     int N=1<<n;
21     f[1<<k]=0;
22     floors[(1<<k)][k]=1;
23     for(int i=0;i<N;i++)
24         for(int j=0;j<n;j++)
25             if((i & (1<<j))>0)
26                 for(int w=0;w<n;w++)
27                     if(((i & (1<<w))==0) && (maps[j][w]!=-1))
28                     {
29                         int r=(1<<w);
30                         int wi=f[i] + floors[i][j]*maps[j][w];
31                         if(f[i+r] > wi)
32                         {
33                             f[i+r]=wi;
34                             for(int l=0;l<n;l++)
35                                 floors[i+r][l]=floors[i][l];
36                             floors[i+r][w]=floors[i][j]+1;
37                         }
38                     }
39     ans=min(ans,f[N-1]);        
40 }
41 
42 int main()
43 {
44     memset(maps,-1,sizeof(maps));
45     scanf("%d%d",&n,&m);
46     for(int i=1;i<=m;i++)
47     {
48         scanf("%d%d%d",&st,&en,&va);
49         if(maps[st-1][en-1]>va || maps[st-1][en-1]==-1)
50             maps[st-1][en-1]=maps[en-1][st-1]=va;
51     }
52     for(int i=0;i<n;i++)
53     {
54         clear();
55         work(i);
56     }
57     cout<<ans<<endl;
58     return 0;
59 }

 

posted @ 2018-03-31 16:27  polar_bear  阅读(218)  评论(0)    收藏  举报
Live2D //博客园自带,可加可不加