翻转数列
题干
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
小Q定义了一种数列称为翻转数列:
给定整数n和m, 满足n能被2*m整除。对于一串连续递增整数数列1, 2, 3, 4..., 每隔m个符号翻转一次, 最初符号为'-';。
例如n = 8, m = 2, 数列就是: -1, -2, +3, +4, -5, -6, +7, +8.
而n = 4, m = 1, 数列就是: -1, +2, -3, + 4.
小Q现在希望你能帮他算算前n项和为多少。
输入描述:
输入包括两个整数n和m(2 <= n <= 10^9, 1 <= m), 并且满足n能被2*m整除。
输出描述:
输出一个整数, 表示前n项和。
输入样例:
8 2
输出样例:
8
解题思路
本题最暴力的方法是把所有数字列出来加和
但是并不是最优解
由于题干中写明 n能被2*m整除
说明:
数列计算有能够优化的做法
最暴力的做法是遍历数列,所以进一步优化时间复杂度会小于O(n),计算前n项和就有推导出计算公式的可能性,时间复杂度O(1)。
根据题干:
当 n = 8, m = 2 时
数列 :-1, -2, +3, +4, -5, -6, +7, +8
发现规律:
-1+3=2=m
-2+4=2=m
-5+7=2=m
-6+8=2=m
当n = 4, m = 1 时
数列 : -1, +2, -3, + 4.
与上面规律相同:
-1+2=1=m
-3+4=1=m
自己生成数据验证
当 n=12 , m=3 时,
前6个数:
-1 -2 -3 +4 +5 +6
-1+4=3
-2+5=3
-3+6=3
所以第一组做和为m*m
一共有 n/(2*m) 组
和为m*m*(n/(2*m)=n*m/2
由于数据量较大 应该用long long 存储
标程
#include <stdio.h>
int main()
{
long long m,n;
scanf("%lld%lld",&n,&m);
printf("%lldn",n/2*m);
return 0;
}
纸牌游戏
题干
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32M,其他语言64M
牛牛和羊羊正在玩一个纸牌游戏。这个游戏一共有n张纸牌, 第i张纸牌上写着数字ai。
牛牛和羊羊轮流抽牌, 牛牛先抽, 每次抽牌他们可以从纸牌堆中任意选择一张抽出, 直到纸牌被抽完。
他们的得分等于他们抽到的纸牌数字总和。
现在假设牛牛和羊羊都采用最优策略, 请你计算出游戏结束后牛牛得分减去羊羊得分等于多少。
输入描述:
输入包括两行。
第一行包括一个正整数n(1 <= n <= 105),表示纸牌的数量。
第二行包括n个正整数ai(1 <= ai <= 109),表示每张纸牌上的数字。
输出描述:
输出一个整数, 表示游戏结束后牛牛得分减去羊羊得分等于多少。
输入样例:
3
2 7 4
输出样例:
5
解题思路
根据题意“牛牛和羊羊都采用最优策略”
最优策略是每次选取都是选数组中剩余最大的元素
所以先将数组降序排序,然后遍历数组,偶数位相加,奇数位相减(如果数组从1号位置开始存储则奇数位相加,偶数位相减)
时间复杂度 nlog(n)
考察知识点:贪心策略
推荐练习题:
Problem - 2037acm.hdu.edu.cn标程
#include <iostream>
#include <algorithm>
using namespace std;
bool cmp(int a,int b){// 定义降序排序规则
return a>b;
}
int main(){
int n,a[100010];
cin>>n;
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a,a+n,cmp);// 排序
int tot;
tot=0;
for(int i=0;i<n;i++){// 遍历数组
if(i%2==0){// 判断偶数位
tot+=a[i];
}else{
tot-=a[i];
}
}
cout<<tot<<endl;
return 0;
}