鉴于博主是个铁憨憨,只A了5题,大佬还请轻喷
Who’s better?
ICPC比赛中,谁通过的题数多,谁排名靠前;在通过题数相同的情况下,谁的罚时少,谁排名靠前;如果前两者都相同,就看最后正确提交的时间,谁早最排名靠前。 现在给你两个队伍的正确通过的题数、罚时和最后正确提交时间,请判断一下,谁的排名更靠前?
输入描述:
只有一组测试样例,两行,每行三个整数
n(0≤n≤13),p(1≤p≤1000),s(1≤s≤300),依次表示两个队的正确通过的题数、罚时和最后正确提交时间。
输出描述:
输出一行(末尾要换行符)。
如果是第1个队排名靠前,输出1;如果是2队,输出2;如果无法分辨,输出"God"。
示例1
输入
1 10 10
1 22 2
输出
1
示例2
输入
1 10 10
2 42 20
输出
2
示例3
输入
1 10 10
1 10 10
输出
God
没什么好说的,按照题目要求直接做
#include <iostream>
#include <algorithm>
using namespace std;
typedef struct Node{
int n, p, s;
Node(int n, int p, int s){
this->n = n;
this->p = p;
this->s = s;
}
bool operator == (const Node & a){
if(this->n == a.n && this->p == a.p && this->s == a.s)
return true;
return false;
}
bool operator > (const Node & a){
if(this->n > a.n)
return true;
else if(this->n < a.n)
return false;
if(this->p < a.p)
return true;
else if(this->p > a.p)
return false;
if(this->s < a.s)
return true;
return false;
}
}Node;
int main(){
int a, b, c;
int x, y, z;
cin >> a >> b >> c >> x >> y >> z;
Node node1(a, b, c), node2(x, y, z);
if(node1 == node2){
cout << "God" << endl;
return 0;
}
if(node1 > node2){
cout << 1 << endl;
}else{
cout << 2 << endl;
}
return 0;
}
Number
Bonnie得到了一个数字n。
现在她想对这个数字不断的做一种操作:
如果n的最后一位数码是0,那么她就把n除以10;
否则她把这个数加上1;
直到n变为一个不大于1的数。
给定n,请问Bonnie需要做多少次操作?
输入描述:
第一行一个数字
T(1≤T≤300000)–样例个数。
每个样例仅一行一个数字
n(1≤n≤10^9) 。
输出描述:
每个样例输出一行一个数字—Bonnie需要做的操作次数。
输入
6
9
99
2
11032
1000000000
62
输出
2
3
9
44
9
13
说明
第一个样例:
9→10→1
第二个样例:
99→100→10→1
没什么好说的,按照题目要求直接做。因为n最多只有九位数,所以一个数最多处理不超过100次,T总共300000个,所以时间完全够
#include <iostream>
#include <algorithm>
using namespace std;
int change_num(int x){
int n = 0;
while(x != 1){
++n;
if(!(x%10))
x /= 10;
else
x++;
}
return n;
}
int main(){
int n;
cin >> n;
while(n--){
int x;
cin >> x;
cout << change_num(x) << endl;
}
return 0;
}
Math Problem
题目描述
已知整数
a,a^3除192的余数是1。求区间[L,R]之间满足条件的a的累加和是多少?
输入描述:
第一行是一个整数
T(1≤T≤10000),表示样例的个数。
每个样例包含两个整数
L,R,1≤L≤R≤10^9。
输出描述:
每行输出一个样例的结果。
示例1
输入
1
1 10
输出
1
基本数学运算。
题目要求是:a^3 % 192 == 1,a^3-1可以转换成其他式子a^3-1 = (a-1)*(a*(a+1)+1)
根据题目要求可以发现 a^3-1 可以整出 192,又因为(a*(a+1)+1)必定是奇数(可以自己计算),所以192 = 64*3中的64必定来自(a-1)。
设(a*(a+1)+1)%3 == 0,这个时候可以证明当且仅当a = 3k+1(k为常数)时 等式成立。所以很容易证明 (a-1)%3==0。
综上:(a-1)能够整除64,也能整除3,所以(a-1)可以整除192。所以a%192=1。
所以a的取值就是 a = 192*k + 1 (k = 1,2,3,4,5.....)
计算区间L~R的a的和,就是区间 (0~R)的和 减去 区间 (0~L-1) 的和。
又 原式 为等差数列,通过公式直接求即可
#include <iostream>
#include <algorithm>
using namespace std;
long long int get_n(int x){
if(x == 0)
return 0;
long long int n = (x-1)/192;
long long int sum = 0;
sum = (1 + n) * n / 2 * 192;
return sum + 1 + n;
}
int main(){
int n;
cin >> n;
while(n --){
int l, r;
cin >> l >> r;
cout << get_n(r) - get_n(l-1) << endl;
}
return 0;
}
Stone
题目描述
有n堆石子排成一排,第i堆石子有ai个石子。
每次,你可以选择任意相邻的两堆石子进行合并,合并后的石子数量为两堆石子的和,消耗的体力等价于两堆石子中石子数少的那个。
请问,将所有的石子合并成一堆,你所消耗的体力最小是多少?
输入描述:
第一行是一个整数
T(1≤T≤20),表示样例的个数。
每个样例的第一行是一个整数n(1≤n≤10000),表示石子堆的数量。
第二行是n个整数
ai(1≤ai≤10^9)
输出描述:
每行输出一个样例的结果。
示例1
输入
2
2
1 2
1
1
输出
1
0
简单贪心。
一开始以为是每次取最小的两个石头求和,再放回原数组。但是这样子和明显不对,看下面例子就知道了。
5
1 1 1 1 1
如果按照上述贪心方法,答案应该是 1+1+1+2=5
但是有更少的方法:固定一个最大的不边,每次都让最小的和最大的求和。
即:1+1+1+1=4
例如:5
1 2 3 4 5
就是:
第一轮 1+5 = 6 sum += 1。数组变成 2 3 4 6
第二轮 2+6 = 8 sum += 2。数组变成 3 4 8
第三轮 3+8 = 11 sum ++ 3。数组编程 4 11
第四轮 4 + 11 = 15 sum += 4。数组编程 15
sum = 10
#include <iostream>
#include <algorithm>
#include <set>
#include <vector>
using namespace std;
vector<int> v;
int main(){
int n;
int T;
cin >> T;
while(T--){
cin >> n;
for(int i=0; i<n; i++){
int t;
cin >> t;
v.push_back(t);
}
sort(v.begin(), v.end());
long long int sum = 0;
for(int i=0; i<v.size()-1; i++){
sum += v[i];
}
cout << sum << endl;
v.clear();
}
return 0;
}
Black & White
题目描述
你有一个长度为 n 的 01 串S,你可以执行最多 m 次操作。
对于每次操作,你可以选择一个位置 i 满足
1≤i≤n,翻转这一位的值,0变成1,1变成0。
定义一个 01 串的价值为其中最长连续0的个数和最长连续1的个数的较大值,求S在经过最多m次操作后的最大价值。
输入描述:
- 第一行一个整数 T ,表示接下来有 T 个样例。
- 首先输入n,m,表示S串的长度n和操作次数m,其中
1≤n≤100000,0≤m≤10000; - 接下来输入一个长度为n的字符串S。
输出描述:
一个整数,表示题面上描述的最大价值。
示例1
输入
2
5 1
00101
2 1
01
输出
4
2
说明
第一个串翻转第三个位置,00001的价值为4;第二个串翻转第一个位置,11的价值为2。
这题的想法时前缀和+二分查找。
首先预处理两个数组 pre1 和 pre0,分表代表1~i个位置上1和0的个数
这样就可以在 O(1) 的时间求出 区间内 1或者0 的个数
然后二分答案:最大长度len。
因为 len 是固定的,所以 l=1,r=len 开始 滑动窗口(时间O(n)),每次移动都判断当前方块内 1或者0的个数是否小于 可以改变的次数m,如果小于等于 则 len 可以成立,可以往更大值二分,否则只能往更小值二分。
时间复杂度:每次二分判断需要O(n)的时间,二分需要log2(n)的时间,所以总时间n*lg(n)时间复杂度ok
#include <iostream>
#include <algorithm>
#include <string>
using namespace std;
string str;
int n, m;
int pre0[100010], pre1[100010];
bool judjed(int len){
int l = 1, r = len;
while(r <= n){
//out << "len = "<< len << " l = " << l << " r = " << r << " 0 = " << pre0[r]-pre0[l-1] << " 1 = " << pre1[r]-pre1[l-1] << endl;
if(pre0[r]-pre0[l-1] <= m || pre1[r]-pre1[l-1] <= m)
return true;
++l, ++r;
}
return false;
}
int get_n(){
int res;
int l=0, r=n;
while(l <= r){
int mid = (l+r)/2;
if(judjed(mid)){
l = mid+1;
res = mid;
}else{
r = mid-1;
}
}
return res;
}
int main(){
int T;
cin >> T;
while(T--){
cin >> n >> m;
cin >> str;
for(int i=1; i<=n; i++){
if(str[i-1] == '0'){
pre0[i] = pre0[i-1]+1;
pre1[i] = pre1[i-1];
}else{
pre0[i] = pre0[i-1];
pre1[i] = pre1[i-1]+1;
}
}
cout << get_n() << endl;
str.clear();
}
return 0;
}