Problem - A - Codeforces
题目大意:有若干个运动员,他们参加的比赛持续时间为t,每个运动员在间隔x的时间后会进行参赛,例如有3个运动员,他们的参赛时刻就为0,x,2x,当一个运动员还在比赛的时候,其他运动员进入,会增加他们一点压力值,求最后所有运动员参加完比赛后的压力值之和.
思路:首先需要确定在一个运动员参赛过程中可能累计的最大压力值,为t/x向下取整,然后判断有多少个人是处于最大压力区间的,这个区间的大小是运动员总数减去区间内最大压力值,然后除满压力值的,其它每个人的压力值依次递减,就可以求出,还需要注意的是需要分类,如果没有人在满压力区间内,那么可能会出现负数,所以要改判一下.
#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
using namespace std;
ll t, n, c, x;
int main(){
cin>>t;
while(t--){
ll ans = 0;
cin>>n>>x>>c;
ll every = c / x;
ll num = n - every; //满压力区间人数
if (num >= 0){
ans += every * num;
ans += (n-num-1)*(n-num)/2;//递减序列
}else{
ans += (n-1)*n/2;
}
cout << ans <<endl;
}
return 0;
}
Problem - B - Codeforces
题目大意:给定一个字符串,求在指定区间内经过一定的变换后,字符串的长度,变换规则是,当前字符重复在字母表中的顺序数,例如a不重复,b重复一次.
思路:直接前缀和.
#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
int t, n;
using namespace std;
ll pre[100005];
string a;
int main(){
cin>>n>>t;
cin>>a;
for (int i = 1; i <= n; ++i)pre[i] = pre[i-1] + (a[i-1]-'a')+1;
while(t--){
int a, b;
cin>>a>>b;
cout<<pre[b] - pre[a-1]<<endl;
}
return 0;
}
Problem - C - Codeforces
题目大意:一个队伍里每个学生有自己的能力值,按照能力值进行排序后,可以将学生们分成若干组,当一个有序小组中任意相邻的两学生能力值差值小于等于x时,才可以成为一个组,否者只能继续分组,你有k次机会,向队伍里添加任意能力值的学生.
思路:贪心,先对数组排个序,只要每次能力值超过了范围,那么就将差值入队,然后对所有的差值进行一个升序排序,每次处理差值最小的,因为每处理掉一个差值,小组数量就会减一,为了使减少的尽可能多,要先从小差值起手.
注意点:当两点之间差值为2x的时候,实际上只需要一个学生就够了,我wa的代码进行判断的时候,采用的是下面这种形式,算法没错但是x和k都是1e14,所以溢出之后答案就错了,应该采用除法求出当前需要添加的个数,然后对个数进行比较.
for (int i = 0; i < index; ++i){
if (dis[i] <= x*(k+1)){ //溢出
ll num = dis[i] / x - (dis[i] % x == 0);
k -=num;
ans--;
}else{
break;
}
ac代码如下
#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
int t, n;
using namespace std;
const int MAX = 2e5+5;
ll a[MAX];
ll dis[MAX];
ll k, x;
int main(){
cin>>n>>k>>x;
for (int i = 1; i <= n; ++i)cin>>a[i];
sort(a+1, a+1+n);
int index = 0;
for(int i = 2; i <= n; ++i){
if (a[i] - a[i-1] > x)dis[index++] = (a[i]-a[i-1]);
}
sort(dis, dis+index);
ll ans = index+1;
for (int i = 0; i < index; ++i){
ll need = ((dis[i])-1)/x; //一种简便写法,因为当正好被两倍整除的时候只需要一个学生插入
if (need>k)break;
else k -= need, ans--;
}
cout << ans <<endl;
return 0;
}
Problem - D - Codeforces
题目大意:给定一些商品,每样商品的价值为2,每件商品有它所需要的购买量,每件商品有它的优惠数量,当你手上物品数量大于等于优惠量之后,就可以半价购买该种商品,请算出最少的购买价格.
思路:模拟题,直接双指针,先将商品进行排序,按优惠价格大进行降序排列,然后左指针来购买优惠量最大的,右指针判断折扣量,具体细节见代码.
注意:又溢出了,我吐了,不然上大分
#include<bits/stdc++.h>
#define ll long long
#define rep(x,y,z) for(int x=y;x<=z;++x)
#define dec(x,y,z) for(int x=y;x>=z;--x)
#define IOS ios::sync_with_stdio(0)
ll t, n;
const int MAXN = 1e5 + 5;
struct Good {
ll num;
ll discount;
};
bool cmp(const struct Good& a, const struct Good& b) {
if (a.discount > b.discount)return true;
else if (a.discount == b.discount) {
return a.num > b.num;
}return false;
}
Good goods[MAXN];
using namespace std;
int main() {
cin >> n;
rep(i, 1, n)cin >> goods[i].num >> goods[i].discount;
sort(goods + 1, goods + 1 + n, cmp);
ll ans = 0;
int r = n, l = 1;
ll now = 0;
while (l <= r) {
ll temp = max(goods[r].discount - now, (ll)0); //判断当前具体右数量还差的优惠数量,优惠数量不能为负
while (temp >= goods[l].num && l <= r) { //如果当前左指针指向的物品全部买下都不够优惠,就继续循环
ans += (ll)2 * goods[l].num; //同时如果到最后没能凑齐优惠金额,要设置停止条件
temp -= goods[l].num;
now += goods[l].num;
l++;
}
if (l > r)break;
ans += temp * (ll)2; //当前左指针指向的物品在满足了优惠数目后还有结余,先只计算优惠金额数目的量
goods[l].num -= temp;
now += temp; //now一定要事实更新
ans += goods[r].num;
now += goods[r].num;
r--;
}
cout << ans << endl;
return 0;
}