切题(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<=50000, di<=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<=200000, m<=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<=500000, ai<=10^9。