A题
- 问不能被3整除且最低位不是3的第 k k k大数,打表预处理即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int Data[MAXN];
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
cin.tie(0);
int t;
int len = 0;
cin >> t;
for(int i=1;i<=10000;i++){
if(i % 10 == 3 || i % 3 == 0) continue;
Data[++len] = i;
}
while(t--){
int n;
cin >> n;
cout << Data[n] << '\n';
}
return 0;
}
B题
- 显然,如果两个数是 o p p o s i t e opposite opposite的,那么他们差的绝对值应该是整个环长度的一半,现在问 c c c的 o p p o s i t e opposite opposite是谁,那么也应该相差环长的一半,所以只需要看 c c c和环长一半之间的关系即可,小于就加上,大于就减去,最后看 a , b , c a,b,c a,b,c是否超过环长,如果是则无解
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int Data[MAXN];
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
int t;
int a, b, c;
cin >> t;
while(t--){
cin >> a >> b >> c;
if(a > b) swap(a, b);
int p = b - a;
int circle = (p << 1);
if(c > circle){
cout << -1 << '\n';
}else{
if(c > p) c -= p;
else c += p;
if(a > circle || b > circle || c > circle) cout << -1 << '\n';
else cout << c << '\n';
}
}
return 0;
}
C题
- 先预处理出 i i i的平方
- 显然左上角的正方形区域每一个都是 i 2 i^2 i2,接下来只需要二分查找给出的 k k k应该处于哪个环状区域内,如果找到发现它等于某个平方项,那么他应在正方形区域的左下角,否则只需要分别向下和左寻找即可
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
ll Data[MAXN];
ll MAX = 1e10;
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
int t;
ll k;
cin >> t;
int len = 1;
for(ll i=1;;i++){
Data[len++] = i * i;
if(i * i > MAX) break;
}
while(t--){
cin >> k;
int p = lower_bound(Data + 1, Data + len + 1, k) - Data;
if(Data[p] == k){
cout << p << " " << 1 << '\n';
}else{
--p;
k -= Data[p];
bool f = false;
for(int i=1;i<=p+1;i++){
if(k == i){
f = true;
cout << i << " " << p + 1 << '\n';
break;
}
}
if(f) continue;
k -= p + 1;
for(int i=1;i<=p;i++){
if(k == i){
f = true;
cout << p + 1 << " " << p - i + 1 << '\n';
break;
}
}
}
}
return 0;
}
D题
给出一个数字 n n n,可以删除其任意一位的数字,也可在其最右侧填充任意数字,问最少需要多少步能够使得这个数字变成 2 2 2的若干次方
- 枚举每一个 2 i ( 0 ≤ i ≤ 63 ) 2^i(0\leq i\leq63) 2i(0≤i≤63),分别求最少的步骤数量再取最小值,每次枚举贪心考虑,因为是改 n n n,所以找 n n n的子序列里面能够等于的, 2 i 2^i 2i的最长前缀,这样只需要把 n n n里其余的部分都删掉, 2 i 2^i 2i的其余部分都加上,即为当前枚举的数字的最小值
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
ll Data[MAXN];
string b[MAXN];
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
int t;
Data[0] = 1;
b[0] = "1";
for(int i=1;i<=63;i++){
Data[i] = Data[i - 1] * 2;
b[i] = to_string(Data[i]);
}
string s;
cin >> t;
while(t--){
cin >> s;
int i = 0;
int j = 0;
int len = s.length();
int ans = INF;
for(int i=0;i<=63;i++){
int num = 0;
int sz = b[i].length();
int k = 0;
for(int j=0;j<len;j++){
if(s[j] == b[i][k]){
k++;
}
}
num = len - k;
num += sz - k;
ans = min(ans, num);
}
cout << ans << '\n';
}
return 0;
}
E题
给你一个字符串,现在删去其任意一个字母,将得到的结果加在其后面,然后将刚才得到的那个删除字母之后的字符串再次删去任意一个字母,进行同样操作,知道字母全部操作完成,现在给你最后的结果,问原字符串和删去字母的顺序
- 举个例子,如果原来的字符串是 a b a c a b a abacaba abacaba,那么现在先删除 b b b,得到 a a c a a aacaa aacaa,将它加在原来字符串的后面,得到 a b a c a b a a a c a a abacabaaacaa abacabaaacaa,再将 a a c a a aacaa aacaa删去 a a a,得到 c c c,加在后面得到 a b a c a b a a a c a a a c abacabaaacaaac abacabaaacaaac,现在给你 a b a c a b a a a c a a abacabaaacaa abacabaaacaa,问原来的那个字符串和删除顺序是什么,答案应该是 a b a c a b a abacaba abacaba和 b a c bac bac
- 可以发现,每个字母都要删除,那么如果从后往前看,第几次出现的字母就应该是倒数第几次被删除的。这样可以得到删除字母的顺序,然后把被删除的字母按顺序整理出来,接下来开始找原串
- 容易理解,第一次被删除的字符在最后得到的串中出现的次数即为它在原串中出现的次数,第二次被删除的字符在最后得到的串中出现的次数即为它在原串中出现次数的两倍,以此类推,那么只需要枚举被删除的字母,就可以得到原来串的长度(记录每个字母的出现次数,然后分别除以它们被删除的顺序数,最后累加即可得到),那么只需要在最后得到的串中从前到后截取这段长度即为原来的字符串
- 最后将这个字符串按照题目要求跑一遍,如果得到的最终字符串是要求的即为有解,否则无解,这里也需要一些编程的技巧(参考标程代码,删除一遍之后赋值回去继续删除,使用 a u t o auto auto关键字会比较方便,具体参考代码如下)
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int Data[MAXN];
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
int t;
string s;
cin >> t;
while(t--){
cin >> s;
int len = s.length();
reverse(s.begin(), s.end());
unordered_map<char, int> mp;
string ans2;
for(int i=0;i<len;i++){
if(!mp.count(s[i])){
ans2.push_back(s[i]);
}
mp[s[i]] += 1;
}
reverse(ans2.begin(), ans2.end());
int b = ans2.length();
len = 0;
for(int i=0;i<b;i++){
len += mp[ans2[i]] / (i + 1);
}
string ans1 = string(s.rbegin(), s.rbegin() + len);
string result = ans1;
string ss = ans1;
for(auto i : ans2){
string temp;
for(auto j : ss){
if(i != j){
temp.push_back(j);
result.push_back(j);
}
}
ss = temp;
}
reverse(s.begin(), s.end());
if(result == s){
cout << ans1 << " " << ans2 << '\n';
}else cout << -1 << '\n';
}
return 0;
}
F题
给你数 n n n和数 k k k,问大于等于 n n n的每位上的不相同的数字个数不超过 k k k的最小数,比如 n = 177890 , k = 2 n=177890,k=2 n=177890,k=2,那么答案应该是 181111 181111 181111
- 看一下怎么推的,首先从左往右 177 177 177没事,到 8 8 8,发现现在不同数字的个数超过 2 2 2了,怎么办呢,因为只能往大了找,不能减小,所以只能把它加一,当然如果这是 9 9 9,那么就往前找,直到找到一个不是 9 9 9的位置,把它加一,你要说前面要全都是 9 9 9怎么办,这不可能,因为如果前面都是 9 9 9,那么就都相同了,也就不存在这个问题了
- 那么后面的数字该怎么办呢?,维持原状肯定不行,因为那这前面直到 0 0 0的数字就都丢了,所以应该把这些数字都变成 0 0 0,这样就不会丢解,这样一次一次的更新,直到符合要求
- 因为最多也就是 10 10 10个不同的数字,这样不停的遍历,差不多几次就会确定一个位置的数字,不会超时
#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <map>
#include <unordered_map>
#include <set>
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 100;
const int INF = 0x3f3f3f3f;
int Data[MAXN];
string solve(){
string n;
int k;
cin >> n >> k;
int len = n.length();
set<char> st;
while(1){
st.clear();
for(auto i : n){
st.insert(i);
}
if(st.size() <= k) return n;
st.clear();
int ptr = 0;
for(; ; ptr++){
st.insert(n[ptr]);
if(st.size() > k){
while(n[ptr] == '9'){
--ptr;
}
n[ptr]++;
for(int i=ptr+1;i<len;i++){
n[i] = '0';
}
break;
}
}
}
return n;
}
int main(){
#ifdef LOCAL
freopen("input.txt", "r", stdin);
freopen("output.txt", "w", stdout);
#endif
ios::sync_with_stdio(false);
int t;
cin >> t;
while(t--){
cout << solve() << '\n';
}
return 0;
}