2017/10/25模拟赛

切题(problem
【问题描述】
Z 和小 G 都是切题好手, 他们经常抢着切题, 今天他们已经
决定好了 n 道要切的题目并准备按照顺序切掉这些题。 每道题都有一
个难度值 di, 两个人都想自己切掉的题难度值之和最大, 但他们又不
屑于切对方切过的题, 于是两人制定了如下规则: 一开始, 决定谁切
下一道题的权利在作为老大的小 Z 手里,拥有这个权利的人可以指定
谁切下一道题, 当被指定的那个人切完题后, 这个权利会转移到没切
这道题的那个人手上(可以是自己) 。 两人都很强, 所以他们总是进
行最优的决策以使自己切到的题难度值之和最大。 F 大爷想知道他们
最后各自切的题的难度值之和。
【输入格式】
第一行一个正整数 n, 表示题数。
接下来 n 个正整数 di, 依次表示第 i 道要切的题的难度值。
【输出格式】
输出两个用空格隔开的整数, 分别表示小 Z 和小 G 切掉的
题的难度值之和。
【样例输入】
4 2
3 3 3
【样例输出】
6 5
【数据范围】
对于 20%的数据, n<=5
对于 40%的数据, n<=50
对于 60%的数据, n<=500
对于 80%的数据, n<=5000
对于 100%的数据, n<=50000di<=100

题解:我们倒着dp,f[i][0/1]表示第i个点主动权在小Z/小G,之后小Z的收益,那么就有2种转移方式(该题切或不切)。

代码如下:

 1 #include<cstdio>
 2 #include<algorithm>
 3 #define MN 50005
 4 using namespace std;
 5 int a[MN],f[MN][2],n,s;
 6 int main()
 7 {
 8     freopen("problem.in","r",stdin);
 9     freopen("problem.out","w",stdout);
10     scanf("%d",&n);
11     for(int i=1;i<=n;i++) scanf("%d",&a[i]),s+=a[i];
12     for(int i=n;i>=1;i--){//接下来权力在小Z 切掉该题并让权力给小G 
13         f[i][0]=max(f[i+1][0],f[i+1][1]+a[i]); //现在权力在小Z 要让自己之后收益尽量大 
14         f[i][1]=min(f[i+1][0],f[i+1][1]+a[i]); //现在权力在小G 要让小Z之后收益尽量小 
15     }
16     printf("%d %d",f[1][0],s-f[1][0]);
17     return 0;
18 }

 

 

开车(car
【问题描述】
老司机小 Q 要在一个十字路口指挥车队开车, 这个十字路口可
以描述为一个 n*n 的矩阵, 其中第 2 行到第 n-1 行都各有一道横向车
道, 第 2 列到第 n-1 列都各有一条纵向车道。 飙车开始前, 小 Q 可以
在每条车道的两端(横向车道为从左到右第 1 格和第 n 格, 纵向车道
为从上到下的第 1 格和第 n 格) 安置一辆大卡车。 安置结束后, 小 Q
可以下令让所有大卡车同时向车道的另一端行驶, 所有的卡车速度都
相同。 小 Q 要合理安排这些卡车, 使得它们在行驶过程中不会相撞;
另外一些格子上有小 C 放置的巨石, 这些格子不能通过卡车。 小 Q
希望安置的卡车最多, 请你求出最多的卡车数。
【输入格式】
第一行两个非负整数 n m, 分别表示十字路口大小和巨石数
量。 接下来 m 行, 每行两个正整数 xi,yi, 表示在第 xi 行第 yi 列有一
个巨石。
【输出格式】
输出一个整数, 表示答案。
【样例输入】
4 3
3 1
3 2
3 3
【样例输出】
1
【数据范围】
对于 20%的数据, n<=5
对于 40%的数据, n<=10
对于 70%的数据, n<=1000
对于 100%的数据, 3<=n<=200000m<=200000

代码如下:

 1 #include<cstdio>
 2 #include<iostream>
 3 #define MN 200005
 4 using namespace std;
 5 bool han[MN],lie[MN];
 6 int n,m,ans;
 7 int main()
 8 {
 9     freopen("car.in","r",stdin);
10     freopen("car.out","w",stdout);
11     scanf("%d%d",&n,&m);
12     for(int i=1;i<=m;i++){
13         int x,y; scanf("%d%d",&x,&y);
14         han[x]=true; lie[y]=true;
15     }
16     for(int i=2;i<n;i++){
17         if(!han[i]) ans++;
18         if(!lie[i]) ans++;
19     }
20     if(n%2==1)if(!han[n/2+1]&&!lie[n/2+1]) ans--;
21     printf("%d",ans);
22     return 0; 
23 }

 

 

学习(study
【问题描述】
巨弱小 D 准备学习, 有 n 份学习资料给他看, 每份学习资料的
内容可以用一个正整数 ai 表示。 小 D 如果在一天内学习了多份资料,
他只能记住这些资料的内容表示成的整数的最大公约数的部分。学习
若干份资料得到的收益是小 D 记下的内容之和, 也就是学习的资料
数乘上这些资料内容的最大公约数。 小 D 今天准备挑一段连续的资
料来学习, 请你告诉他最大的收益是多少。
【输入格式】
第一行一个正整数 n, 表示资料数。
接下来 n 个正整数 ai, 分别表示每份资料的内容。
【输出格式】
输出一个整数, 表示答案。
【样例输入】
5 3
0 60 20 20 20
【样例输出】
80
【数据范围】
对于 20%的数据, n<=100
对于 40%的数据, n<=1000
对于 70%的数据, n<=100000
对于 100%的数据, n<=500000ai<=10^9

 

posted @ 2017-10-30 16:02  Beginner_llg  阅读(185)  评论(0编辑  收藏  举报