淘汰赛2题目题解

问题 E:

暴力DP
根据题意可推出四种状态:
1.当上一个音符和当前音符都为-1时,可得到dp[i][a[i]]=dp[i-1][a[i-1]]+score[a[i-1]][a[i]];
2.当上一个音符为-1,当前音符不为-1时,可得到dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+score[j][a[i]]);
3.当上一个音符不为-1,当前音符为-1时,可得到dp[i][j]=max(dp[i][j],dp[i-1][a[i-1]]+score[a[i-1]][j]);
4.当上一个音符和当前音符都不为-1时,可得到dp[i][k]=max(dp[i][k],dp[i-1][j]+score[j][k]);
只需枚举每次的状态即可。

代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<queue>
 7 #include<vector>
 8 #include<stack>
 9 #include<map>
10 #include<set>
11 #include<cmath>
12 #include<cctype>
13 #include<ctime>
14 #define INF 0x3f3f3f3f
15 #define PI acos(-1.0)
16 #define MOD 998244353
17 typedef long long ll;
18 typedef unsigned long long ull;
19  
20 using namespace std;
21  
22 int dp[1005][1005];
23 int score[1005][1005];
24 int a[1005];
25  
26 int main()
27 {
28 //  freopen("test1.in","r",stdin);
29 //  freopen("test1.out","w+",stdout);
30     int t;
31     scanf("%d",&t);
32     while(t--)
33     {
34         memset(dp,0,sizeof(dp));
35         int n,m,maxn=0;
36         scanf("%d%d",&n,&m);
37         for(int i=1;i<=m;i++)
38             for(int j=1;j<=m;j++)
39                 scanf("%d",&score[i][j]);
40         for(int i=1;i<=n;i++)
41             scanf("%d",&a[i]);
42         for(int i=2;i<=n;i++)
43         {
44             if(a[i-1]>0&&a[i]>0)
45                 dp[i][a[i]]=dp[i-1][a[i-1]]+score[a[i-1]][a[i]];
46             else if(a[i-1]>0&&a[i]<0)
47             {
48                 for(int j=1;j<=m;j++)
49                     dp[i][j]=max(dp[i][j],dp[i-1][a[i-1]]+score[a[i-1]][j]);
50             }
51             else if(a[i-1]<0&&a[i]<0)
52             {
53                 for(int j=1;j<=m;j++)
54                     for(int k=1;k<=m;k++)
55                         dp[i][k]=max(dp[i][k],dp[i-1][j]+score[j][k]);
56             }
57             else
58             {
59                 for(int j=1;j<=m;j++)
60                     dp[i][a[i]]=max(dp[i][a[i]],dp[i-1][j]+score[j][a[i]]);
61             }
62         }
63         for(int i=1;i<=n;i++)
64             maxn=max(maxn,dp[n][i]);
65         printf("%d\n",maxn);
66     }
67 //  fclose(stdin);
68 //  fclose(stdout);
69     return 0;
70 }
View Code

问题 H:

F = A*X^2 + B*X + C 由于A,B,C(1<=A<=10000,1<=B<=10000,1<=C<=10000) 可得X>=-B/(2*A)时,F(X)一定是单调递增的

所以对于同一部番来说,第I级的动漫肯定比第I+1级动漫花费的钱少。所以对于每部番我们只需要维护我们还没有看的集数最小

的那一集就可以了,使用优先队列维护,算法流程如下:

1.将N部番的第一集放入优先队列

2.从优先队列中取花费最小的一集并弹出队列,假设该集为第I部番的第J集,花费为F(I,J)

3.将F(I,J)加至答案,将第I部番的第J+1集加入优先队列

4.如果已经加了M集,则结束,否则跳转至步骤2

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long Lint;
 4 const int max_n = 3*1e5+1e2;
 5 const Lint mod = 998244353;
 6  
 7 struct Node{
 8     Lint a,b,c;
 9     int dep;
10     Lint val;
11     friend bool operator <(const Node &n1,const Node &n2){
12         return n1.val>n2.val;
13     }
14 };
15  
16 int n,m;
17 priority_queue<Node> que;
18  
19 void solve(){
20     Node node;
21     scanf("%d %d",&n,&m);
22     for(int i=0;i<n;i++){
23         scanf("%lld %lld %lld",&node.a,&node.b,&node.c);
24         node.val=node.a+node.b+node.c;
25         node.dep=1;
26         que.push(node);
27     }
28     Lint res=0;
29     while(m--){
30         res+=que.top().val;
31         node=que.top();
32         que.pop();
33         node.dep++;
34         node.val=node.a*node.dep*node.dep+node.b*node.dep+node.c;
35         que.push(node);
36     }
37     printf("%lld\n",res);
38 }
39  
40 int main(){
41     solve();
42     return 0;
43 }
View Code

问题 G:

从根节点开始遍历,对于遍历到的节点统计它的子节点中叶子节点数量X,答案增加(X+1)/2向下取整,对于它的非叶子子节点,则加入遍历序列,继续遍历。

扫描二维码关注公众号,回复: 3591261 查看本文章

需要注意的是,由于节点有2000000个,所以并不能使用递归遍历(递归深度过深会爆栈,详情请了解堆内存和栈内存),故而我这里是使用BFS进行遍历。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int d[2123456],v[2123456];
 4 vector<int> maps[2123456];
 5 queue<int> team;
 6 int main(){ 
 7     int n;
 8     scanf("%d",&n);
 9     memset(d,0,sizeof(d));
10     memset(v,0,sizeof(v));
11     for(int i=1;i<n;i++){
12         int l,r;
13         scanf("%d%d",&l,&r);
14         maps[l].push_back(r);maps[r].push_back(l);
15         d[l]+=1;d[r]+=1;
16     }
17     team.push(1);
18     int ans = 0;
19     while(!team.empty()){
20         int x = team.front();team.pop();
21         v[x] = 1;
22         int p,gs = 1;
23         for(int i=0;i<maps[x].size();i++){
24             p = maps[x][i];
25             if(v[p]) continue;
26             if(d[p]==1) gs+=1;
27             else{
28                 team.push(p);
29             }
30         }
31         ans = ans + (gs/2); 
32     }
33     printf("%d",ans);
34     return 0;
35 }
View Code

问题 K:

这道题是个模拟题目,每一步怎么做题目中都有说。

我们可以重载运算符来方便地进行文科理科,不同科目不同要求的排序。

对于第一次专业分配,我们可以对每一个专业维护进入它的最低分数,来判断是否存在有人所有分数相同但是名额不够的情况。

对于第二次专业分配使用优先队列,map或者set维护当前的最优专业进行分配即可,需要注意没有专业可以分配的情况。

也就是代码量、细心和debug能力的考验,在一堆考验智商的题目中算是良心题目了。

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<ctime>
  4 #include<cstring>
  5 #include<string>
  6 #include<cstdio>
  7 #include<map>
  8 #include<vector>
  9 #include<algorithm>
 10 using namespace std;
 11 struct Data {
 12     int a[6];
 13     int number;
 14     int sum;
 15     void read() {
 16         sum = 0;
 17         for (int i = 0; i<5; i++) {
 18             cin >> a[i];
 19             sum += a[i];
 20         }
 21     }
 22     bool operator<(const Data&pt)const {
 23         if (sum != pt.sum) return sum>pt.sum;
 24         if (a[3] != 0) {//wenke
 25             if (a[0] != pt.a[0]) return a[0]>pt.a[0];
 26             if (a[2] != pt.a[2]) return a[2]>pt.a[2];
 27             if (a[1] != pt.a[1]) return a[1]>pt.a[1];
 28             if(a[3] !=pt.a[3]) return a[3]>pt.a[3];
 29             return number<pt.number;
 30         }
 31         else {
 32             if (a[1] != pt.a[1]) return a[1]>pt.a[1];
 33             if (a[2] != pt.a[2]) return a[2]>pt.a[2];
 34             if (a[0] != pt.a[0]) return a[0]>pt.a[0];
 35             if(a[4] !=pt.a[4]) return a[4]>pt.a[4];
 36             return number<pt.number;
 37         }
 38     }
 39     bool operator==(const Data&pt)const {
 40         if (a[0] != pt.a[0]) return a[0] == pt.a[0];
 41         if (a[2] != pt.a[2]) return a[2] == pt.a[2];
 42         if (a[1] != pt.a[1]) return a[1] == pt.a[1];
 43         if (a[3] != pt.a[3]) return a[3] == pt.a[3];
 44         return a[4] == pt.a[4];
 45     }
 46 };
 47 struct zyData {
 48     string zy[6];
 49     int fc;
 50     void read() {
 51         for (int i = 0; i<5; i++) cin >> zy[i];
 52         cin >> fc;
 53     }
 54 };
 55 struct xzyData {
 56     int num;
 57     Data pre;
 58 };
 59 struct xzyData2 {
 60     int num;
 61     string name;
 62     bool operator<(const xzyData2 &pt)const {
 63         if (num != pt.num)
 64             return num > pt.num;
 65         else
 66             return name < pt.name;
 67     }
 68 };
 69 vector<Data> wk, lk;
 70 vector<Data> wk2, lk2;
 71 vector<zyData> stu_zy;
 72 map<string, xzyData> maps;
 73 map<xzyData2,int> mapswk,mapslk;
 74 void read(int x) {
 75     Data pt;
 76     pt.read();
 77     if (pt.a[3] == 0 && pt.a[4] == 0) {
 78         while (true) cout << "ERROR文理相同" << endl;
 79     }
 80     pt.number = x;
 81     if (pt.a[3] == 0) lk.push_back(pt);
 82     else wk.push_back(pt);
 83 }
 84 string xzyname;
 85 xzyData pts;
 86 string ans[110000];
 87 int main() {
 88 //  freopen("3.in","r",stdin);
 89 //  freopen("3.out","w+",stdout);
 90     int n, m;
 91     scanf("%d", &n);
 92     for (int i = 0; i<n; i++) read(i);
 93     for (int i = 0; i<n; i++) {
 94         zyData pt; pt.read(); stu_zy.push_back(pt);
 95     }
 96     scanf("%d", &m);
 97     for (int i = 0; i<m; i++) {
 98         int number;
 99         cin >> xzyname >> number;
100         pts.num = number;
101         for (int j = 0; j<5; j++) {
102             pts.pre.a[j] = 0x3f3f3f3f;
103         }
104         maps[xzyname] = pts;
105     }
106     sort(wk.begin(), wk.end());
107     sort(lk.begin(), lk.end());
108     for (int i = 0; i<wk.size(); i++) {
109         int number = wk[i].number;
110         int ok = 0;//是否分配成功
111         for (int j = 0; j < 5; j++) {
112             if (wk[i].a[3] != 0 && stu_zy[number].zy[j][0] >= 'a'&&stu_zy[number].zy[j][0] <= 'z')
113                 continue;
114             if (wk[i].a[4] != 0 && stu_zy[number].zy[j][0] >= 'A'&&stu_zy[number].zy[j][0] <= 'Z')
115                 continue;
116             if (maps.find(stu_zy[number].zy[j]) == maps.end())
117                 continue;
118             if (maps[stu_zy[number].zy[j]].num <= 0) {
119                 if (maps[stu_zy[number].zy[j]].pre == wk[i]);
120                 else
121                     continue;
122             }
123             ok = 1;
124             ans[number] = stu_zy[number].zy[j];
125             maps[stu_zy[number].zy[j]].pre = wk[i];
126             maps[stu_zy[number].zy[j]].num = maps[stu_zy[number].zy[j]].num - 1;
127             break;
128         }
129         if (ok) continue;
130         if (stu_zy[number].fc == 0) {
131             ans[number] = "0";
132             continue;
133         }
134         wk2.push_back(wk[i]);
135     }
136     for (int i = 0; i<lk.size(); i++) {
137         int number = lk[i].number;
138         int ok = 0;//是否分配成功
139         for (int j = 0; j < 5; j++) {
140             if (lk[i].a[3] != 0 && stu_zy[number].zy[j][0] >= 'a'&&stu_zy[number].zy[j][0] <= 'z')
141                 continue;
142             if (lk[i].a[4] != 0 && stu_zy[number].zy[j][0] >= 'A'&&stu_zy[number].zy[j][0] <= 'Z')
143                 continue;
144             if (maps.find(stu_zy[number].zy[j]) == maps.end())
145                 continue;
146             if (maps[stu_zy[number].zy[j]].num <= 0) {
147                 if (maps[stu_zy[number].zy[j]].pre == lk[i]);
148                 else
149                     continue;
150             }
151             ok = 1;
152             maps[stu_zy[number].zy[j]].pre = lk[i];
153             ans[number] = stu_zy[number].zy[j];
154             maps[stu_zy[number].zy[j]].num = maps[stu_zy[number].zy[j]].num - 1;
155             break;
156         }
157         if (ok) continue;
158         if (stu_zy[number].fc == 0) {
159             ans[number] = "0";
160             continue;
161         }
162         lk2.push_back(lk[i]);
163     }
164     map<string, xzyData>::iterator ptsp;
165     for (ptsp = maps.begin(); ptsp != maps.end(); ++ptsp) {
166         if (ptsp->second.num <= 0)
167             continue;
168         xzyData2 np;
169         np.name = ptsp->first;
170         np.num = ptsp->second.num;
171         if (ptsp->first[0]>='A'&&ptsp->first[0]<='Z')
172             mapswk[np] = 1;
173         else
174             mapslk[np] = 1;
175     }
176     for (int i = 0; i < wk2.size(); i++) {
177         if (mapswk.empty()|| mapswk.begin()->first.num<=0) {
178             ans[wk2[i].number] = "0"; continue;
179         }
180         ans[wk2[i].number] = mapswk.begin()->first.name;
181         xzyData2 np;
182         np.name = mapswk.begin()->first.name;
183         np.num = mapswk.begin()->first.num - 1;
184         mapswk.erase(mapswk.begin());
185         if (np.num <= 0) {
186             continue;
187         }
188         else {
189             mapswk[np] = 1;
190         }
191     }
192     for (int i = 0; i < lk2.size(); i++) {
193         if (mapslk.empty() || mapslk.begin()->first.num <= 0) {
194             ans[lk2[i].number] = "0"; continue;
195         }
196         ans[lk2[i].number] = mapslk.begin()->first.name;
197         xzyData2 np;
198         np.name = mapslk.begin()->first.name;
199         np.num = mapslk.begin()->first.num - 1;
200         mapslk.erase(mapslk.begin());
201         if (np.num <= 0) {
202             continue;
203         }
204         else {
205             mapslk[np] = 1;
206         }
207     }
208     /*
209     for(int i=0;i<wk.size();i++)
210         cout<<wk[i].sum<<endl;
211     for(int i=0;i<lk.size();i++)
212         cout<<lk[i].sum<<endl;*/
213     for (int i = 0; i < n; ++i)
214         cout << ans[i] << endl;
215 //  fclose(stdin);
216 //  fclose(stdout);
217     return 0;
218 }
View Code

问题 C:

题意,n个排在一条线上的球 围绕其中心旋转,现移动k个球,使其每个球到新中心的距离的平方的和最小。

思路,将k个球移动至剩余(n-k)个球的新中心,则这k个球到新中心距离的平方都为0则,一定会是最小值。所以实际上并不是移动k个球而是删除k个球,使得剩余(n-k)个球到新中心距离平方和最小。题中提示新中心其实就是平均值。那么其实就是在求n个球删除k个球,剩余n-k个球的方差。

解法:I=Σ(1~n)[(ai-center)*(ai-center)]拆开得到:I=Σai*ai-2*d*Σai+nd*d (这里的I即所求,n代指n-k,d表示新中心的位置) 再把d=[Σ(1~n)[ai]]/n带入即可化简。

化简过程如图

 

公式可得只需在排序后求得前缀和与前缀平方和即可。

代码:

 1 #include<bits/stdc++.h>
 2  
 3 #define ms(a,x) memset(a,x,sizeof(a))
 4 using namespace std;
 5  
 6 #define N 50005
 7 #define MAX 100002
 8  
 9 typedef long long ll;
10 const int maxt=1e4+5;
11 const int maxn=1e4+5;
12 const int mod=998244353;
13  
14 ll a[N];
15 ll x[N],y[N];
16  
17 int main(){
18     int t;
19     cin>>t;
20  
21  
22     while(t--){
23         int n,k;
24         cin>>n>>k;ll minn=99999999999999999999;
25         for(int i=1;i<=n;i++)
26             cin>>a[i];
27         if(n==k||n==k+1){
28             printf("0\n");continue;
29         }
30         sort(a+1,a+n+1);
31         ms(x,0);ms(y,0);
32         for(int i=1;i<=n;i++){
33             x[i]=x[i-1]+a[i];
34             y[i]=y[i-1]+a[i]*a[i];
35         }
36         for(int i=1;i<=k+1;i++){
37             ll aa=y[i+n-k-1]-y[i-1];
38             ll bb=x[i+n-k-1]-x[i-1];
39             aa*=(n-k)*1ll;
40             ll cc=aa-bb*bb;
41             minn=min(minn,cc);
42         }
43         printf("%.3f\n",(double)minn/(double)(n-k));
44     }
45     return 0;
46 }
View Code

猜你喜欢

转载自www.cnblogs.com/xfww/p/9790436.html
今日推荐