链接
A. Required Remainder
题意 : t组数据,每组给出x,y,n 在1到n中找出最大的数满足模x等于y
思路 : 直接二分查找,假定
,那么
就属于0到
,直接二分这个倍数,找出最大解就可以了
LL x, y, n;
void solve () {
x = read(), y = read(), n = read();
LL L = 0, R = 1e9 + 1, res = 0;
while(L <= R) {
LL mid = L + R >> 1;
LL tmp = x * mid + y;
if(tmp <= n) {
res = tmp;
L = mid + 1;
} else {
R = mid - 1;
}
}
printf("%lld\n", res);
}
B. Multiply by 2, divide by 6
题意; T组数据,每组给出一个数
,对于这个数你可以进行若干次操作,使得这个数乘于
或者除于
(前提是可以整除),你想要获得1,求出最小的操作数,或者说不存在
思路:首先给出的
是大于等于1的,所以如果可以转换成功的话,那么最后一步一定是这个数除于
之后变成1,而除于6就必须要求这个数本身含有因子3,乘于2只会改变质因子2的个数,除于6则是消除一个2,消除一个3,所以先统计下质因子除了2和3以外是否还有其他质因子,有的话直接输出
,如果只含2和3的话,还需要保证2的个数不超过3的个数,因为我们只能增加2,每次消除2同时需要消除3
所以当且仅当质因子只含2和3,且2的因子数不超过3的因子数才可以,答案为
void solve () {
LL n = read(), num2 = 0, num3 = 0;
while(n != 1 && n % 2 == 0) {
n /= 2;
++ num2;
}
while(n != 1 && n % 3 == 0) {
n /= 3;
++ num3;
}
if(n != 1) {
puts("-1");
return ;
}
if(num2 > num3) {
puts("-1");
} else {
LL dis = num3 - num2;
printf("%lld\n", num3 + dis);
}
}
C. Move Brackets
题意:给出一个括号序列(保证左括号数目等于右括号),然后每次操作可以将一个字符移动到序列开头或者序列结尾,求出移到合法所需的最小步数
思路:
先放结论: 就是不规范的括号对数
证明 首先对于一个合法的括号对(),之后在它的两边套一个新的变成(())也是合法的,所以我们对于这个题的移动策略完全可以处理为,不合法的左括号全放在最左边,右括号全放在最右边,合法的对数都消除掉,同时只需要统计不合法的左括号数目就可以了,因为我们把它放在最左边那就一定有一个括号可以跟他想匹配,(不一定是和最右边的那个),所以这个其实就是不合法的数目,用栈维护就可以了,不懂的话就自己画一画
void solve () {
int n = read();
scanf("%s", str + 1);
stack<char>sta;
int res = 0;
for(int i = 1; i <= n; ++ i) {
if(str[i] == '(') {
sta.push(str[i]);
} else {
if(sta.empty()) {
++ res;
} else {
sta.pop();
}
}
}
printf("%d\n", res);
}
D. Zero Remainder Array
题意: 有一种超能力初始效果为0,每天这个效果会加一,每天可以选择是否使用,但只有一次机会,可以给任意一个数增加上这个效果使得这个数变大,他需要把所有的数都变成
的整数倍(mod后为0),求问至少需要多少天
思路:
这个其实简单,读入的时候把所有的数mod k处理一下,等于0的不管,不等于0的都需要加上(k-剩余的数),如果全部的需要的数都不重复就直接取最大的,扫一遍就过了,如果有重复的数,那就是出现次数最多的数中最大的那个数为最后一天,假设这个数需要m,出现了sum次,共有n个数,那么答案就是
LL arr[maxn], res[maxn], n, k;
vector<LL> vec;
map<LL, LL> mp;
void solve () {
vec.clear();
mp.clear();
cin >> n >> k;
LL cnt = 0;
for(int i = 1; i <= n; ++ i) {
cin >> arr[i];
LL tmp = k - (arr[i] % k);
res[i] = tmp == k ? 0 : tmp;
mp[res[i]] ++;
if(res[i]) {
cnt = max(cnt, mp[res[i]]);
}
}
LL ans = 0;
for(int i = 1; i <= n; ++ i) {
if(mp[res[i]] == cnt) {
ans = max(ans, res[i]);
}
}
ans = max(0ll, ans + (cnt - 1) * k + 1);
printf("%lld\n", ans);
}
E1. Reading Books (easy version)
题意: n本书,两个孩子,每本书有需要读的时间和两个孩子是否喜欢它 这三个属性,之后每个孩子都需要读k本自己喜欢的,但是他们在同一时间必须要读同一本书,求问最少多少时间可以让两者都读完要求的书
思路
这个其实很简单,读入的时候,开三个
,一个储存两者都喜欢的,一个储存a喜欢的,一个储存b喜欢的,之后把a,b两个数组都从小到大排序,然后取以两者最少的个数来取出来合并当成同一个,放入大数组,然后
大数组,取前k个之和就行了
vector<int> vec_L, vec_R, res;
int n, k, arr[maxn];
void solve () {
cin >> n >> k;
for(int i = 1; i <= n; ++ i) {
cin >> arr[i];
int a, b;
cin >> a >> b;
if(a && b) {
res.emplace_back(arr[i]);
} else if(a) {
vec_L.emplace_back(arr[i]);
} else if(b) {
vec_R.emplace_back(arr[i]);
}
}
sort(vec_L.begin(), vec_L.end());
sort(vec_R.begin(), vec_R.end());
auto szl = vec_L.size(), szr = vec_R.size();
for(int i = 0; i < szl && i < szr; ++ i) {
res.emplace_back(vec_L[i] + vec_R[i]);
}
sort(res.begin(), res.end());
auto szres = res.size();
if(szres < k) {
cout << -1;
} else {
int sum = 0;
for(int i = 0; i < k; ++ i) {
sum += res[i];
}
cout << sum << endl;
}
}