Codeforces Round #739 (Div. 3)
A题
题意:找出第K个不能被3整除且末尾不是3的数
思路:暴力打表
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
auto tmp = { (cout << args << ' ', 0)... };
cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
vector<int>v;
for (int i = 1; i < 3000; i++) {
if (i % 3 != 0) {
if (i % 10 != 3)v.push_back(i);
}
}
/*cout << v.size() << "\n";
for (auto i : v)cout << i << " ";*/
int t;
cin >> t;
while (t--) {
int k;
cin >> k;
cout << v[k-1] << "\n";
}
return 0;
}
B题
题意:若干个数按顺时针排列成圆,且关于圆心一一对称,告诉你其中对称的一组数 a 、 b ,求与 c 对称的数
思路:计算出总人数
n
u
m
=
2
∗
a
b
s
(
a
−
b
)
num=2*abs(a-b)
num=2∗abs(a−b),再进行判断即可。
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
auto tmp = { (cout << args << ' ', 0)... };
cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t;
cin >> t;
while (t--) {
int a, b, c;
cin >> a >> b >> c;
int t = abs(a - b);
int num = 2 * t;
if (a > num || b > num || c > num)cout << -1 << "\n";
else {
if (c - t > 0) cout << c - t << "\n";
else if (c + t <= num)cout << c + t << "\n";
else cout << -1 << "\n";
}
}
return 0;
}
C题
题意:给你个矩阵,这个矩阵以某种方式填充数,问你第 k 个数的坐标是多少?
思路:注意到每列第一个为这层最大的数,根据给定步数找到最大的起始位置然后计算步数差手动回退下即可。
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
auto tmp = { (cout << args << ' ', 0)... };
cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
vector<ll> x;
x.push_back(1);
ll d = 3;
ll sum = 1;
while (1) {
x.push_back(x.back() + d);
d += 2;
sum = sum + d;
if (sum > MOD)break;
}
x.push_back(x.back() + d);
//for (auto i : x)cout << i << "\n";
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int pos = lower_bound(x.begin(), x.end(), n) - x.begin();
//cout << pos << "\t"<<x[pos]<<"\n";
int d = x[pos] - n;
int x, y;
if (d <= pos)x = 1 + d, y = pos + 1;
else x = 1 + pos, y = pos - (d - (1 + pos));
cout << y << " " << x << "\n";
//cout << pos << " "<<x[pos]<<"\n";
}
return 0;
}
D题
题意:
给定数字num,给定两种操作
- 1.从右边加入一个数
- 2.删除任意一个数
问最少多少次操作后所给数字能变成 2 n 2^n 2n的形式
思路:
注意到因为是从右边加入一个数字所以之前数字能在一个2的某次幂满足要求越多越好
我们将 [ 2 0 , 2 64 ] [2^0,2^{64}] [20,264]所有的数打表打出来,然后一个一个计算这个数变成2的某次幂的所需步骤取最小的即可。
匹配的过程类似于KMP的过程
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
auto tmp = { (cout << args << ' ', 0)... };
cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 5e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;
vector<ll>v;
vector<ll>num[64];//2的64
void init() {
ll t = 1;
for (ll i = 1; i < 64; i ++) v.push_back(t),t*=2;
for (int i = 0; i < v.size(); i++) {
ll t = v[i];
while (t)num[i].push_back(t % 10), t /= 10;
reverse(num[i].begin(), num[i].end());
}
}
int solve(int n,int pos) {//计算从n变为num[pos]所需步数
vector<ll>t;
while (n)t.push_back(n % 10), n /= 10;
reverse(t.begin(), t.end());
int cnt = 0, i = 0, j = 0;
while(j < t.size()&& i < num[pos].size()) {
if (num[pos][i] == t[j])i++, j++;
else j++,cnt++;
}
cnt = cnt + (num[pos].size() - i) + (t.size() - j);
return cnt;
}
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
init();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
int ans = INF;
for (int i = 0; i < v.size(); i++) ans = min(ans,solve(n, i));
cout << ans << "\n";
}
return 0;
}
E题
题意:假设有这样一个字符串 s 和一个空字符串 t , 字符串 s 可以执行下列操作直至其为空:
- 先令 t=t+s
- 再移除 s 中所有的某字母
现在给你一个 t 串,问你能否倒推出 s 串和字母的删除顺序。
思路:
首先对于给定的字符串从后往前出现过的记录那么第一次出现的就都属于删除字母,具体来说删除字母的顺序应该是顺序统计出来的删除字母的逆序。
记录下字母 a 的出现次数 cnta ,即 a 在原串中的出现次数为 numa=cnta/i ,所有字母的 num 之和即为原串 s 的长度,那 s 也就可以随之确定了
确定了s和删除字母的顺序然后按题意模拟一遍判断就行。
#include<bits/stdc++.h>
#include <unordered_map>
using namespace std;
template<class...Args>
void debug(Args... args) {//Parameter pack
auto tmp = { (cout << args << ' ', 0)... };
cout << "\n";
}
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>pll;
typedef pair<int, int>pii;
const ll N = 1e5 + 5;
const ll INF = 0x7fffffff;
const ll MOD = 1e9 + 7;
string solve(string t,string s) {//模拟题目过程
string ans = t;
for (int i = 0; i < s.length(); i++) {
string temp;
for (int j = 0; j < t.length(); j++) if (t[j] != s[i])temp.push_back(t[j]);
t = temp;
ans += t;
}
return ans;
}
int main() {
ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int t;
cin >> t;
while (t--) {
string temp, s;
cin >> temp;
map<char, int>m;
for (int i = temp.length() - 1; i >= 0; i--) {
if (!m[temp[i]])s.push_back(temp[i]);
m[temp[i]]++;
}
reverse(s.begin(), s.end());
int len = 0;
for (int i = 0; i < s.size(); i++)len += m[s[i]] / (i + 1);
string tt = temp.substr(0, len);
if (temp == solve(tt,s))cout << tt << " " << s << "\n";
else cout << -1 << "\n";
}
return 0;
}