Codeforces Round #739 [Div. 3]
感觉这场的难度区分度挺高的,前面三道题手速题,后面还是有点难度(对我这种小白来说),运气好排进前1000,有点意思~~。
A. Dislike of Threes
题意: 将大于0的整数中,去掉 能被3整除的数 和 以3结尾的数,从小到大排成一个序列,输出这个序列的第k个元素。
能被3整除的数:i % 3 != 0
以3结尾的数:i % 10 != 3
#include<bits/stdc++.h>
using namespace std;
const int N=10100;
int a[N];
void ok(){
int cnt = 0;
for (int i = 1; i <= 3000; i++) {
if (i % 3 != 0 && i % 10 != 3) {
a[++cnt] = i;
}
}
}
int main(){
int _;
cin >> _;
ok();
while(_--){
int k;
cin >> k;
cout << a[k] << endl;
}
return 0;
}
B. Who’s Opposite?
题意: 一些人围成一个圈,(人数为偶数),这些人从数字1开始顺时针编号,每个人可以透过圆的中心看对面的人。(其中箭头表示谁在看谁),输入三个数,a, b, c;
其中:a看向b,求c看向的是谁?
题解: 通过观察,这个圆的最大数是:max = abs(a-b)×2
,那么需要保证a,b,c都要小于等于这个最大数,如果存在大于max的数,则不满足题意,输出-1。
设对面的数是x,有两种情况:
① c > x
② c < x
But都可以归结为:
(
(
c
−
1
)
+
(
m
a
x
/
2
)
)
%
t
+
1
((c-1) + (max / 2)) \;\% \;t + 1
((c−1)+(max/2))%t+1
#include<bits/stdc++.h>
using namespace std;
const int N=10100;
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _;
cin >> _;
while(_--){
int a, b, c;
cin >> a >> b >> c;
int maxn = abs(a - b) * 2;
if (a > maxn || b > maxn || c > maxn ) cout << -1 << endl;
else cout << (c - 1 + (maxn / 2)) % maxn + 1 << endl;
}
return 0;
}
C. Infinity Table
题意: 构造一个无限行无限列的表,构造方法如图所示,给出一个k,求出这个k的坐标位置。
通过观察发现,所有的完全平方数,均在最左边的一列,所以分类讨论:
存一个int sk = sqrt(k);
其中 (sk 是 sqrt(k)的缩写,这样好理解点)
①
s
k
∗
s
k
=
=
k
sk * sk == k
sk∗sk==k,证明 k 这个数恰好是完全平方数,那么这个数的位置就在
(
s
q
r
t
(
k
)
,
1
)
(sqrt(k), 1)
(sqrt(k),1) 即
(
s
k
,
1
)
(sk, 1)
(sk,1),如下图所示:
![](https://img-blog.csdnimg.cn/fc6adb3970b449c59cdcd4ec4d6fbf26.png?)
② k − s k ∗ s k = = s k + 1 k - sk * sk == sk + 1 k−sk∗sk==sk+1 ,证明 k 这个数恰好在,下一行下一列,即1的斜对角位置,如下图所示。
![](https://img-blog.csdnimg.cn/5ca20b64ceb04ffdb690e34c072a2e7c.png?)
③ k − s k ∗ s k ≤ s k k - sk * sk ≤ sk k−sk∗sk≤sk ,证明k这个数在第sk列,如下图所示:
![](https://img-blog.csdnimg.cn/8234177a3ed2405ab82aead8394e2059.png?)
④ k − s k ∗ s k > s k k - sk * sk > sk k−sk∗sk>sk ,证明k这个数在第sk行,如下图所示:
![](https://img-blog.csdnimg.cn/c41c582751444b1aba83b27a1f1a965b.png?)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=10100;
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _;
cin >> _;
while(_--){
int k, sk;
cin >> k;
sk = sqrt(k);
int r, c;
if (sk * sk == k) {
r = sk;
c = 1;
} else if (k - sk * sk == sk + 1) {
r = sk + 1;
c = sk + 1;
} else if (k - sk * sk <= sk) {
r = k - sk * sk;
c = sk + 1;
} else {
r = sk + 1;
c = sk + 1 - (k - sk * sk - sk - 1);
}
cout << r << ' ' << c << endl;
}
return 0;
}
D. Make a Power of Two
题意: 给定一个整数n,每一次可以选择一下一项执行:
- 删除这个数任一数位的数字。(运算前的数字只有一个数字,运算后的数字是“空”,这是可以接受的)
- 向右加一位。
注意,如果在删除某个数字后,它包含前导零,则不会删除。例如,如果你从数字301中删除数字3,结果就是数字01(而不是1)。
需要执行最少的操作数,使得数字为2的任意次方,结果必须没有前导零。
样例:
如果n=1052,需要操作2次,往右边加4,删掉5.
如果n=8888,需要操作3次,连续删掉3次8
思路: ,删除任意一位数,加上任意一位数,貌似都与2的幂没什么关系,所以通过字符串的角度来思考这个问题。
n的范围是: 1 ≤ n ≤ 1 0 9 1≤n≤10^9 1≤n≤109,那么字符串的长度便是: l e n ≤ 9 len≤9 len≤9,对于任意字符串,想要变成2的幂,最多可以通过len+1次操作使之变成2的幂,即全部删完,添加一个2。所以字符串的范围最大不会超过1e18,通过计算是大于 2 60 2^{60} 260的, 比赛的时候,粗略估计了一下,以为是 2 62 2^{62} 262~ 2 63 2^{63} 263,就往大了开 。
再去从左往右遍历字符串,比如说1052,就匹配102,对应匹配到1024,再往后面加上一个4
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#define int long long
using namespace std;
int l[100];
int mi2[100];
int n;
char ch[100][50];
char t[50];
char s[50];
void init()
{
mi2[0] = 1;
for (int i = 1; i <= 62; i++)
mi2[i] = mi2[i - 1] << 1;
for (int i = 0; i <= 62; i++)
{
while (mi2[i])
{
t[++l[i]] = mi2[i] % 10 + '0';
mi2[i] /= 10;
}
for (int j = 1; j <= l[i]; j++)
ch[i][l[i] - j + 1] = t[j];
}
char mi63[40] = "9223372036854775808";
char mi64[40] = "18446744073709551616";
for (int i = 0; i <= 30; i++)
{
ch[63][i + 1] = mi63[i];
ch[64][i + 1] = mi64[i];
}
l[63] = strlen(mi63);
l[64] = strlen(mi64);
}
int ck(int x)
{
int idx1 = 0, idx2 = 0;
while (idx1 < n && idx2 < l[x])
{
while (s[idx1 + 1] != ch[x][idx2 + 1] && idx1 < n && idx2 < l[x])
idx1++;
if (s[idx1 + 1] == ch[x][idx2 + 1] && idx1 < n && idx2 < l[x])
{
idx1++;
idx2++;
}
}
int res = (n - idx2) + l[x] - idx2;
return res;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
init();
int _;
cin >> _;
while (_--)
{
memset(s, 0, sizeof s);
cin >> s + 1;
n = strlen(s + 1);
int ans = n + 1;
for (int i = 0; i <= 64; i++)
{
ans = min(ans, ck(i));
}
cout << ans << endl;
}
return 0;
}
E. Polycarp and String Transformation
P先生有一个字符串s,P先生执行以下操作,知道字符串s为空(t最初是一个空字符串)
在字符串t的右边加上字符串s,即t=t + s
。
以第一个例子为例:
input:abacabaaacaac
output:abacaba bac
输出中的第二个字符串bac指的是:
input的字符串从右往左每个字符出现的顺序即 cab 的反转
这个是求得output中第一个字符串的长度。
for (int i = 0; i < lens1; i++) len += cnt[s1[i] - 'a'] / (i + 1);
后面就直接暴力删字符就行了
最后看是否跟原来输入的s相等,即可
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <deque>
#include <fstream>
#include <iostream>
#include <queue>
#include <stack>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
using namespace std;
int _;
int cnt[26];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin >> _;
while (_--)
{
memset(cnt, 0, sizeof cnt);
string s;
cin >> s;
int lens = s.size();
string s1;
for (int i = lens - 1; i >= 0; i--)
{
cnt[s[i] - 'a']++;
if (cnt[s[i] - 'a'] == 1)
s1 += s[i];
}
int lens1 = s1.size();
reverse(s1.begin(), s1.end());
int len = 0;
for (int i = 0; i < lens1; i++)
{
len += cnt[s1[i] - 'a'] / (i + 1);
// cout << i << ' ' << len << endl;
}
string ss = s.substr(0, len);
// cout << ss << endl;
string str1 = ss, str2 = ss;
for (int i = 0; i < lens1; i++)
{
string str3;
for (int j = 0; j < str1.size(); j++)
{
if (str1[j] != s1[i])
str3 += str1[j];
}
str2 += str3;
str1 = str3;
}
if (str2 == s)
cout << ss << ' ' << s1 << endl;
else
cout << -1 << endl;
}
}
F1、F2. Nearest Beautiful Number(明天更,困了)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1000010;
int a[N];
int n, m, k, cnt;
string s, ans;
void dfs(int x, string t) {
if (cnt > k) return;
if (t >= ans) return;
string str = t;
while (str.length() < n) str += '9';
if (str < s) return;
if (x == n) {
ans = min(ans, t);
return;
}
for (int i = 0; i <= 9; i++) {
if (++a[i] == 1) cnt++;
dfs(x + 1, t + (char)(i + 48));
if (a[i]-- == 1) cnt--;
}
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int _;
cin >> _;
while(_--){
cin >> s >> k;
for (int i = 0; i <= 10; i++) a[i] = 0;
n = s.length();
ans = "999999999";
cnt = 0;
dfs(0, "");
cout << ans << endl;
}
return 0;
}