Codeforces Round #653 (Div. 3)

打比赛确实是比学东西实用技巧来的快,,
废话不多说,上题,

A. Required Remainder
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given three integers x,y and n. Your task is to find the maximum integer k such that 0≤k≤n that kmodx=y, where mod is modulo operation. Many programming languages use percent operator % to implement it.
In other words, with given x,y and n you need to find the maximum possible integer from 0 to n that has the remainder y modulo x.
You have to answer t independent test cases. It is guaranteed that such k exists for each test case.

求n以内,模x等于y的最大数,
咱还是真的憨憨的去模了一波,,

#include<bits/stdc++.h>
using namespace std;
int x,y,n;
int t;
int main(){
	scanf("%d",&n);
	while(n--){
		scanf("%d%d%d",&x,&y,&t);
		int r=t%x;
		if(r==y)cout<<t<<endl;
		else if(r>y)cout<<t-(r-y)<<endl;
		else if(r<y)cout<<t-x+(y-r)<<endl;
	}
} 

真就是保证模x等于y然后找符合不大于n的条件的数嘛,
然而真正的大佬是这样做的

signed main()
{
	IO_OP;
	
	int t;
	cin >> t;
	while(t--) {
		int x, y, n;
		cin >> x >> y >> n;
		cout << (n - y) / x * x + y << endl;
	}
	
}

我tm,,,
先来看看人家怎么做的,
首先第一步,n除以x再乘以x,这个利用整除的性质,就是会寻找一个n以内最大x的倍数,然后+y,这不就变成最大的余数为y的数了吗,
但是仔细想想这么出来的数范围就变大了,上限变成了n+y;
题上要求不大于n,这么想,数字n经过这一系列操作上限会变成n+y,且符合条件,那么数字n-y经过这一系列操作不就变成n了吗,也符合条件,,,,似乎这样强行理解,也是有道理的,,
有道理个头哟,,
我试图证了证,这么做的正确性,,
首先n/x再*x会得到一个n以内最大的x的倍数,这个数的范围是n-x,到n,怎么也不会小于n-x,最多大于n,这一点利用整除的性质很好证,然后再加上y,那么这个数的范围就变了,n+x+y,到n+y,且符合模x等于y的条件,然后再一想,这个数都能取到n+y了,还不是n+y以内最大的符合条件数了吗,而且不会超范围,
其实本题收获最大的还是n整除x再乘以x,,会得到n以内最大的x的倍数,,,,

B. Multiply by 2, divide by 6
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given an integer n. In one move, you can either multiply n by two or divide n by 6 (if it is divisible by 6 without the remainder).
Your task is to find the minimum number of moves needed to obtain 1 from n or determine if it’s impossible to do that.
You have to answer t independent test cases.

给定一个数,乘以2算一步,除以6算一步,问最少多少步到1,不能则输出负一
有点像拆分素数,要变成1,乘以二肯定还要再除以6,相当于除以3,
除以6和除以3
如果除以6的次数是n,那么拆解为2和3的个数都有n,如果除以3的次数是m,那么3还有多于2的m步,
所以拆分成3的个数要大于2的个数,
拆不成1输出-1就不多说了,
步数的计算,手里有3的个数n和2的个数m
2的个数m其实就是单独除以6的个数,权重是1
3的个数多于2的个数的那部分就是2再除以6的部分,权重是2,
所以就是ans=m+2
(n-m)
也就是两倍3的个数加2的个数
我的代码属实菜,,,
上大神的代码

signed main()
{
	IO_OP;
	
	int t;
	cin >> t;
	while(t--) {
		int n;
		cin >> n;
		int sa = 0, na = 0;
		while(n % 2 == 0) n /= 2, sa++;
		while(n % 3 == 0) n /= 3, na++;
		if(n != 1 || sa > na) {
			cout << -1 << endl;
			continue;
		}
		cout << na + na - sa << endl;
	}
	

C. Move Brackets
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given a bracket sequence s of length n, where n is even (divisible by two). The string s consists of n2 opening brackets ‘(’ and n2 closing brackets ‘)’.
In one move, you can choose exactly one bracket and move it to the beginning of the string or to the end of the string (i.e. you choose some index i, remove the i-th character of s and insert it before or after all remaining characters of s).
Your task is to find the minimum number of moves required to obtain regular bracket sequence from s. It can be proved that the answer always exists under the given constraints.
Recall what the regular bracket sequence is:
“()” is regular bracket sequence;
if s is regular bracket sequence then “(” + s + “)” is regular bracket sequence;
if s and t are regular bracket sequences then s + t is regular bracket sequence.
For example, “()()”, “(())()”, “(())” and “()” are regular bracket sequences, but “)(”, “()(” and “)))” are not.
You have to answer t independent test cases.

其实就是判断括号是否匹配,遇到哪一步不匹配了,整个序列最小的移动次数,每一个括号可移动到队首或队尾
队里啥都没有的时候肯定左括号进去都行啊,顺便记一下已经积攒的左括号的个数用变量L表示
右括号进来的时候,如果栈里有左括号,那左括号数量-1,没啥,,
栈里要是没有左括号,就得补救一波,把右括号移动到队尾吧,由于整个序列左括号和右括号数量相同,这个右括号肯定能匹配上的,所以已经积攒的左括号数量不减少,然后后面的就再匹配就完事了

#include<bits/stdc++.h>
using namespace std;
int t;
char s[2005] ;
int n;
int main(){
	scanf("%d",&t);
	while(t--){
		scanf("%d",&n);
		scanf("%s",s);
		int l=0;
		int r=0;
		int ans=0;
		int Lack=0;
		for(int i=0;i<n;i++){
			if(s[i]=='('){
				
				 l++;
			}
			else {
				if(l<=0){
					ans++;
				}
				else if(l>0){
					l--;
				}			
			}
		}
		//cout<<"ans=";
		cout<<ans<<endl;
	}
}

D. Zero Remainder Array
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You are given an array a consisting of n positive integers.
Initially, you have an integer x=0. During one move, you can do one of the following two operations:
Choose exactly one i from 1 to n and increase ai by x (ai:=ai+x), then increase x by 1 (x:=x+1).
Just increase x by 1 (x:=x+1).
The first operation can be applied no more than once to each i from 1 to n.
Your task is to find the minimum number of moves required to obtain such an array that each its element is divisible by k (the value k is given).
You have to answer t independent test cases.

D这个题,一上来就有思路,,但是这个鬼东西真的考验实战经验,
问将数组内每个数都补充成k的倍数需要用一个连续的数列跨度多少,,
其实每个数字我们关心的只是它差几能补成目标数的倍数,也就是k-(a[i]%k),由于补充的数是连续的,对于k-(a[i]%k),相同的数组成员,必须转一轮0~k-1才能再轮到它,所以说先统计每个k-(a[i]%k)出现最高的次数,这个其实就表示了要转几轮0到k-1,然后就是最高次数相同了要取完k-(a[i]%k)大的那个数,

思路都不是什么事,这个题就卡操作,,首先是这个1e9的k,,wc储存余数0到k-1就要开1e9的数组呢??我还真去开了1e9的数组,主席说的对,dev太垃圾了,,数组开大了报错报的是return 1 exist
我一度以为编译器坏了,正打着cf呢忽然编译器炸了,我1觉得我代码是对的,没编译就交CF上去了,提示数组开大了,wc,,这咋办啊,,1e9的余数,,仔细一看原来n只有2e5,开2e5的数组也不行啊,,,,余数不一定再2e5之内,,,,,map<int,int>cnt;
映射确实挺好用,,,
然后就是这个题还会爆int,
我翻开榜一的代码一查,这代码没有long long,歪歪斜斜的每行上都写着‘int’三个字。过不了题,我横竖睡不着,仔细看了半夜,才从声明里看出字来,满本都写着两个字是‘long long ’!”
我tm看到了这一句,,
#define int ll
typedef long long ll;
之后他下面用的全是int,,我就用int交题wa了无数次

#include <bits/stdc++.h>
#define IO_OP std::ios::sync_with_stdio(0); std::cin.tie(0);
#define F first
#define S second
#define V vector
#define PB push_back
#define MP make_pair
#define EB emplace_back
#define ALL(v) (v).begin(), (v).end()
#define debug(x) cerr << #x << " is " << x << endl
#define int ll

using namespace std;

typedef long long ll;
typedef pair<int, int> pi;
typedef V<int> vi;

const int INF = 1e9 + 7;

signed main()
{
	IO_OP;
	
	int t;
	cin >> t;
	while(t--) {
		int n, k;
		cin >> n >> k;
		map<int, int> cnt;
		int mx = -1;
		for(int i = 0; i < n; i++) {
			int tt;
			cin >> tt;
			if(tt % k == 0) continue;
			tt %= k;
			cnt[tt]++;
			mx = max(mx, cnt[tt] * k - tt);
		}
		cout << mx + 1 << endl;
	}

}




后面比赛没做到,之后补,7.30还要考高数,

©️2020 CSDN 皮肤主题: 深蓝海洋 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值