Codeforces Round #451 (Div. 2) 题解
文章目录
A. Rounding
- 题意
给你一个非负整数,需要你输出将其舍入到最接近的整数,且末尾是 0 0 0。
/**
*@filename:A
*@author: pursuit
*@created: 2021-08-12 14:05
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n;
void solve(){
int temp = n % 10;
if(temp >= 5){
n = n / 10 * 10 + 10;
}
else{
n = n / 10 * 10;
}
cout << n << endl;
}
int main(){
cin >> n;
solve();
return 0;
}
-
解题思路
取最低位判断是否 ≥ 5 \geq5 ≥5即可,据此作出改变, n ÷ 10 × 10 + n ≥ 5 ? 10 : 0 n\div 10\times 10 + n\geq 5 ?10:0 n÷10×10+n≥5?10:0。
-
AC代码
B. Proper Nutrition
-
题意
给你 n , a , b n,a,b n,a,b三个整数,找出是否存在 x , y x,y x,y使得 a x + b y = n ax+by=n ax+by=n。
-
解题思路
直接暴力即可,枚举 x x x即可确定 y y y,而 n n n为 1 e 7 1e7 1e7, O ( n ) O(n) O(n)复杂度可以通过。
-
AC代码
/**
*@filename:B
*@author: pursuit
*@created: 2021-08-12 14:08
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,a,b;
void solve(){
int maxx = n / b;
for(int i = 0; i <= maxx; ++ i){
int temp = n - i * b;
if(temp % a == 0){
cout << "YES" << endl;
cout << temp / a << " " << i << endl;
return;
}
}
cout << "NO" << endl;
}
int main(){
cin >> n >> a >> b;
solve();
return 0;
}
C. Phone Numbers
-
题意
给你每个人的电话号码信息,需要你对每一个人的电话号码信息进行处理,即若甲的电话号码 x x x是甲的电话号码 y y y的后缀,那么就删除 x x x。按格式输出处理后的信息。
-
解题思路
好题。考察细节,对字符串的处理以及一些必要的数据存储技能。我们首先需要存储每个人的姓名以及电话信息,这里我们采用 v e c t o r vector vector存储,同时我们需要确定每个人的编号方便索引存储位置以及需要通过编号来确定姓名,这里采用了两个 m a p map map实现。当然,我们也可以只用一个结构体来实现存储。注意一定要判断每个人是否之前已经存储过了,若存储过直接在原地方存储即可。
处理好之后,我们来分析怎么删除,如果 x x x是 y y y的后缀,那么第一点就是 l e n ( a ) ≤ l e n ( b ) len(a) \leq len(b) len(a)≤len(b)。所以我们可以先对每个人的电话号码按长度大小排序,这样能保证长度要求。那么之后就是要比较是否相等了,根据 x , y x,y x,y自然能索引到 x x x在 y y y中的起始判断位置,即使 l e n ( y ) − l e n ( x ) len(y) - len(x) len(y)−len(x),故只需判断 y . s u b s t r ( l e n ( y ) − l e n ( x ) ) = x y.substr(len(y) - len(x))=x y.substr(len(y)−len(x))=x即可。
-
AC代码
/**
*@filename:C
*@author: pursuit
*@created: 2021-08-12 14:31
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 22 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,cnt;
map<int,string> p1;
map<string,int> p2;
vector<string> ans[N];
string s,num;
//按字符串长度排序。
bool cmp(string a,string b){
return a.size() < b.size();
}
void solve(){
cout << p2.size() << endl;
for(int i = 1; i <= cnt; ++ i){
//处理每个人的号码。
sort(ans[i].begin(),ans[i].end(),cmp);
for(int j = 0; j < ans[i].size(); ++ j){
string num1 = ans[i][j];
for(int k = j + 1; k < ans[i].size(); ++ k){
string num2 = ans[i][k];
if(num2.substr(num2.size() - num1.size()) == num1){
ans[i].erase(ans[i].begin() + j);
j --;
break;
}
}
}
cout << p1[i] << " " << ans[i].size() << " ";
for(int j = 0; j < ans[i].size(); ++ j){
cout << ans[i][j] << " ";
}
cout << endl;
}
}
int main(){
cin >> n;
for(int i = 1; i <= n; ++ i){
cin >> s;
if(!p2[s]){
p2[s] = ++ cnt;
p1[cnt] = s;
}
int id = p2[s],tot;
cin >> tot;
while(tot -- ){
cin >> num;
ans[id].push_back(num);
}
}
solve();
return 0;
}
D. Alarm Clock
-
题意
给你一个 n n n时钟,其响铃时间为 a i a_i ai,需要你至少关闭多少个闹钟才能使得连续 m m m分钟响铃次数 < k <k <k。
-
解题思路
使劲贪即可。注意到,我们必然是 ≥ k \geq k ≥k时再关闭,且一定是关闭触发这个条件时刻的一些闹钟,使得响铃次数变成 k − 1 k-1 k−1,至此题解。
-
AC代码
/**
*@filename:D
*@author: pursuit
*@created: 2021-08-12 15:28
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e6 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n,m,k,x;
int a[N],maxx;
ll cnt;
void solve(){
ll ans = 0;
for(int i = i; i <= maxx; ++ i){
if(i < m)cnt += a[i];
else cnt += (a[i] - a[i - m]);
if(cnt >= k){
ans += cnt - k + 1;
a[i] -= (cnt - k + 1);
cnt = k - 1;
}
//cout << cnt << endl;
}
printf("%lld\n", ans);
}
int main(){
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; ++ i){
scanf("%d", &x);
maxx = max(maxx,x);
a[x] ++;
}
solve();
return 0;
}
E. Squares and not squares
-
题意
给定 n n n个数,你可以对其中每个数进行 + − 1 +-1 +−1操作,问使得这 n n n个数有 n / 2 n/2 n/2个非平方数和 n / 2 n/2 n/2个平方数的最少操作次数。
-
解题思路
对于平方数变非平方数,+1即可(0需要+2),对于非平方数变平方数,选择最近的那个即可。将这些数的消耗排序,取最小的即可。
-
AC代码
/**
*@filename:E
*@author: pursuit
*@created: 2021-08-12 15:39
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 2e5 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n;
ll x;
ll a[N],b[N];
int cnta,cntb;
ll cal(ll *a,int x,int n){
ll res = 0;
sort(a + 1,a + 1 + n);
for(int i = 1; i <= x; ++ i){
//cout << a[i] << endl;
res += a[i];
}
return res;
}
void solve(){
if(cnta == cntb){
puts("0");
}
else{
printf("%lld\n",cnta > cntb ? cal(a,cnta - n / 2,cnta) : cal(b,cntb - n / 2,cntb));
}
}
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; ++ i){
scanf("%lld", &x);
int temp = sqrt(x);
if(temp * temp == x){
if(x)a[++cnta] = 1;
else a[++cnta] = 2;
}
else{
b[++cntb] = min((temp + 1) * (temp + 1) - x,x - temp * temp);
}
}
solve();
return 0;
}
F. Restoring the Expression
-
题意
给定一个数值字符串 s s s,需要你分割成 a , b , c a,b,c a,b,c使得 a , b , c a,b,c a,b,c不包含前导零,且 a + b = c a+b=c a+b=c。 n ≤ 1 0 6 n\leq 10^6 n≤106
-
解题思路
注意到 n n n的范围,所以我们需要在 O ( n ) O(n) O(n)时间内解决。我们发现,只需要枚举 = 号的位置,而根据其合理性 m a x ( l e n A , l e n B ) ≤ l e n C ≤ m a x ( l e n A , l e n B ) + 1 max(lenA,lenB) \leq lenC \leq max(lenA,lenB) + 1 max(lenA,lenB)≤lenC≤max(lenA,lenB)+1,那么确定了 l e n C lenC lenC,则有4种可能。 l e n A = l e n C , l e n B = n − ( l e n A + l e n C ) , 同 理 l e n B = l e n C , l e n A = n − . . . , l e n A = l e n C − 1 , l e n B = n − ( l e n A + l e n C ) , 同 理 l e n B = n − . . . . lenA = lenC,lenB = n - (lenA + lenC),同理lenB = lenC,lenA = n -...,lenA = lenC - 1,lenB = n - (lenA + lenC),同理lenB = n - .... lenA=lenC,lenB=n−(lenA+lenC),同理lenB=lenC,lenA=n−...,lenA=lenC−1,lenB=n−(lenA+lenC),同理lenB=n−....
所以实际上我们是可以在线性时间内完成字符串的分割的,关键在于判断 a + b = c a+b=c a+b=c,大数首先排除 O ( n 2 ) O(n^2) O(n2),那么有什么方法呢?这里引入 h a s h C o d e hash\ Code hash Code,也叫散列值,就是将字符串映射成一个数值,一个数值代表一个字符串。字符串hash,【算法学习】字符串哈希(Hash),大家可以看一下一些 b l o g blog blog学习。于是如果我们比较字符串相等,那么可以直接比较它们的 h a s h C o d e hash\ Code hash Code,这样就达到了 O ( 1 ) O(1) O(1)的字符串相等判断,即用空间换时间。字符串 h a s h hash hash需要我们确定 b a s e base base和 m o d mod mod,然后对应的 h a s h hash hash公式即为 h a s h [ i ] = ( h a s h [ i − 1 ] × b a s e + s [ i ] − ′ 0 ′ ) % m o d hash[i] = (hash[i - 1] \times base + s[i] - '0') \% mod hash[i]=(hash[i−1]×base+s[i]−′0′)%mod,对于此方法,我们需要将 b a s e base base和 m o d mod mod取大一点,这样才能避免数值冲突。如果要获取字串的 h a s h hash hash值,那么其对应公式即为 r e s = ( ) ( h a s h [ r ] − h a s h [ l − 1 ] × b a s e r − l + 1 ) % m o d + m o d ) % m o d ( 由 于 是 减 法 , 所 以 可 能 是 负 值 , 需 要 + m o d 取 余 res = ()(hash[r] - hash[l -1] \times base^{r-l+1})\% mod + mod)\%mod(由于是减法,所以可能是负值,需要+mod取余 res=()(hash[r]−hash[l−1]×baser−l+1)%mod+mod)%mod(由于是减法,所以可能是负值,需要+mod取余)$
那么这里还需提到的一点就是如何得到 a + b a+b a+b,就是直接散列值相加即可,因为每个值可以唯一代表一个字符串。
h a s h hash hash算法各种各样,能写出适合自己的 h a s h hash hash模板即可。
-
AC代码
/**
*@filename:F
*@author: pursuit
*@created: 2021-08-12 15:55
**/
#include <bits/stdc++.h>
#define debug(a) cout << "debug : " << (#a)<< " = " << a << endl
using namespace std;
typedef pair<int,int> pii;
typedef long long ll;
const int N = 1e6 + 10;
const int P = 1e9 + 7;
const int INF = 0x3f3f3f3f;
int n;
int base = 10;//base为基底,其代表了为几进制数。
ll Hash[N],p[N];
string s;
//字符串hash,写法有很多种。
//不过思路都是一样的,就是要用唯一的数值确定一段字符串。所以也跟mod有关。
void init(){
n = s.size();
for(int i = 0; i < n; ++ i){
Hash[i + 1] = (Hash[i] * base % P + s[i] - '0') % P;
}
p[0] = 1;//base ^ i
for(int i = 0; i < n; ++ i){
p[i + 1] = p[i] * base % P;
}
}
int get(int l,int r){
//获取[l,r]子串。
if(r < 0 || l - 1 < 0 || r - l + 1 < 0)return 0;
return (Hash[r] - Hash[l - 1] * p[r - l + 1] % P + P) % P;
}
bool check(int lenA,int lenB,int lenC){
if(lenA > lenC || lenB > lenC)return false;
if(lenA < 0 || lenB < 0)return false;
if(s[lenA] == '0' && lenB != 1)return false;
if(s[0] == '0' && lenA != 1)return false;
if((get(1,lenA) + get(lenA + 1,lenA + lenB)) % P != get(lenA + lenB + 1,n)){
return false;
}
return true;
}
void print(int lenA,int lenB,int lenC){
for(int i = 0; i < lenA; ++ i){
putchar(s[i]);
}
putchar('+');
for(int i = lenA; i < lenA + lenB; ++ i){
putchar(s[i]);
}
putchar('=');
for(int i = lenA + lenB; i < n; ++ i){
putchar(s[i]);
}
}
void solve(){
for(int lenC = 1; lenC < n; ++ lenC){
if(s[n - lenC] == '0' && lenC > 1)continue;//排除前导0的情况。
//cout << lenC << endl;
if(check(lenC,n - 2 * lenC,lenC)){
print(lenC,n - 2 * lenC,lenC);
break;
}
else if(check(n - 2 * lenC,lenC,lenC)){
print(n - 2 * lenC,lenC,lenC);
break;
}
else if(check(lenC - 1,n - 2 * lenC + 1,lenC)){
print(lenC - 1,n - 2 * lenC + 1,lenC);
break;
}
else if(check(n - 2 * lenC + 1,lenC - 1,lenC)){
print(n - 2 * lenC + 1,lenC - 1,lenC);
break;
}
}
}
int main(){
cin >> s;
init();
solve();
return 0;
}

浙公网安备 33010602011771号