目录
比赛链接: Codeforces Round #653 (Div. 3)
1374A. Required Remainder
1374B. Multiply by 2, divide by 6
1374C. Move Brackets
1374D. Zero Remainder Array
1374E1. Reading Books (easy version)
题意:给定一个X, Y, N,要求找到一个最大的K(K <= N),使得K % X == Y。
主要代码:
int main(){
int t;
scanf("%d", &t);
while(t--){
int x, y, n;
scanf("%d %d %d", &x, &y, &n);
int c = n % x;
if(c >= y){
printf("%d\n", n - (c - y));
}
else{
printf("%d\n", n - (c + x - y));
}
}
return 0;
}
题意:给定一个N,问能不能通过不断地乘2或除6得到1。
思路:如果N%3!=0,则是-1.否则迟早可以得到1。
主要代码:
int main(){
int t;
scanf("%d", &t);
while(t--){
LL n;
scanf("%lld", &n);
int ans = 0;
bool flag = 1;
while(n != 1){
if(n % 3 != 0) {
flag = 0;
break;
}
if(n % 6 == 0) ans++, n /= 6;
else ans++, n *= 2;
}
if(n == 1) printf("%d\n", ans);
else printf("-1\n");
}
return 0;
}
题意:给定一个长度为N的括号序列,保证N为偶数,且左括号与右括号数量相等。问通过几次操作可以使得括号序列是符合括号规则的。操作方法为:选定一个括号将其移至首位或末位。
思路:只要最终的括号序列为:(((())))类似这样的,就必定是规则的,因此只要将不符合括号规则的左括号全提到首位或者不符合括号规则的右括号全移至末位。
主要代码:
int main(){
int t;
scanf("%d", &t);
while(t--){
int n;
scanf("%d", &n);
string s;
cin >> s;
int op = 0;
int ans = 0;
for(int i = 0; i < n; ++i){
op += s[i] == '(' ? 1 : -1;
if(op < 0 && s[i] == ')') ans++, op++;
}
printf("%d\n", ans);
}
return 0;
}
题意:给定一个长度为N的数组A与一个K,有一个隐含的操作数X,X初始为0。每次操作可以有两种选择,一种是选择一个A[i],使得A[i] = A[i] + X, X = X + 1;另一个种是直接X = X + 1。问经过几次操作可以使得数组A中的任意一个元素模K都为0。
思路:将A[i]转化为A[i] % K,可以想到,X实际上也是模K的循环,每次循环如果某一个A[i] + X == K,则此时可以将一个A[i]转化为符合要求的数,那么对于一个A[i],假设A[i]出现的次数为cnt次,则至少需要cnt个循环才能将所有与A[i]相等的数转化成符合要求的数,所以找到出现次数最多的A[i]。那么有可能X不是完整的cnt次循环就可以将所有数转化为满足要求的数。所以要计算出最后一次循环只需要循环几次再加上K*(cnt - 1)次就是答案。
主要代码:
inline bool cmp(int a, int b){return a > b;}
int main(){
int t;
scanf("%d", &t);
while(t--){
int n, k;
scanf("%d %d", &n, &k);
vector a(n);
map mp;
int Max = 0, x = -1;
bool flag = 0;
for(int i = 0; i < n; ++i){
scanf("%d", &a[i]);
a[i] %= k;
mp[a[i]]++;
if(a[i] != 0) flag = 1;
else continue;
if(Max < mp[a[i]]){
Max = mp[a[i]];
x = k - a[i];
}
else if(Max == mp[a[i]]){
if(x < k - a[i]) x = k - a[i];
}
}
if(flag) printf("%lld\n", k * 1LL * Max - k + x + 1);
else printf("0\n");
}
return 0;
}
题意:给N本书,阅读第 本数需要花费的时间,Alice和Bob有自己喜欢的数,根据输入中的 和 确定。给定一个K,问,如果要选出一个书集,书集中Alice喜欢读的有至少K本,Bob喜欢读的也至少有K本,且阅读完这个书集要花费的时间最少。这个最少时间是多少。
思路:如果选择只有Alice喜欢的书中时间最少的书和选择只有Bob喜欢的书中时间最少的书,两者时间相加大于Alice和Bob同时喜欢的书所要花的时间,那么选择共同喜欢的书肯定更优。否则的话就选择前面两本书。若有只有其中一方喜欢的书没得选了,那肯定优先选择共同喜欢的书。
代码:
#define pb push_back
vector t;
vector a, b, ab;
bool cmp(int x, int y){return t[x] < t[y];}
inline int cal(int x){
int ans = ab.size();
int l = 0, r = ab.size() - 1;
while(l <= r){
int mid = l + r >> 1;
if(t[ab[mid]] <= x) l = mid + 1;
else r = mid - 1, ans = mid;
}
return ans;
}
int main(){
int n, k;
scanf("%d %d", &n, &k);
t.resize(n);
for(int i = 0; i < n; ++i){
int l, r;
scanf("%d %d %d", &t[i], &l, &r);
if(l && !r) a.pb(i);
if(r && !l) b.pb(i);
if(l && r) ab.pb(i);
}
if(a.size()) sort(a.begin(), a.end(), cmp);
if(b.size()) sort(b.begin(), b.end(), cmp);
if(ab.size()) sort(ab.begin(), ab.end(), cmp);
if(min(b.size() + ab.size(), a.size() + ab.size()) < k) return printf("-1\n"), 0;
int cura = 0, curb = 0;
int pre = 0;
int A, B;
A = k, B = k;
int ans = 0;
while(1){
if(cura == a.size() || curb == b.size()) break;
int Mint = t[a[cura]] + t[b[curb]];
int pos = cal(Mint);
for(int i = pre; i < pos; ++i){
A--;
B--;
ans += t[ab[i]];
if(A == 0 || B == 0) break;
}
if(A == 0 || B == 0) break;
ans += t[a[cura]];
cura++;
A--;
ans += t[b[curb]];
curb++;
B--;
if(A == 0 || B == 0) break;
pre = pos;
}
while(A > 0){
if(pre != ab.size()){
A--;
B--;
ans += t[ab[pre]];
pre++;
}
else ans += t[a[cura]], cura++, A-- ;
}
while(B > 0){
if(pre != ab.size()){
B--;
ans += t[ab[pre]];
pre++;
}
else B--, ans += t[b[curb]], curb++;
}
printf("%d\n", ans);
return 0;
}