文章目录
A.Dislike of Threes
题意:
特殊序列:不带有 可以被 3 整除的数 和 以 3 结尾的数
eg:1,2,4,5,7,8,10,11,14,16,…
输出该序列的第 n 个数
思路:
t 和 n 都不大,直接暴力就能过
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int a[N], p;
void init()
{
for(int i=1; p <= 1000; i++) {
if(i%3 == 0 || i%10 == 3) continue;
else a[++p] = i;
}
}
int main()
{
init();
int t; cin >> t;
while(t--) {
int n; cin >> n;
cout << a[n] << endl;
}
return 0;
}
B.Who’s Opposite?
题意:
一群人(偶数)按顺时针编号坐在一个圆桌里,给出 a,b,c
已知 a 和 b 相对,求 c 和谁相对,不存在则输出 -1
思路:
一开始卡题了,懂题意,但思维混乱,一直wa
以下思路借鉴某大佬~
- 显然人数总数 n 等于2倍的 abs(a-b)
- 如果 a, b, c有任意一个大于 n 的时候,输出 -1
- 如果 a 与 b 在 n 中不是相对而坐的,输出 -1
- 求 c 相对的人就是第一步求总人数的逆运算
注:在圆桌上,如果p ≤ n/2,则 p 的对面为 p + n/2,否则 p 的对面为 p - n/2
代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int t; cin >> t;
while(t--) {
int a, b, c; cin >> a >> b >> c;
if(a > b) swap(a, b);// 使 a < b
int d = b - a, n = 2 * d;// d,abs(a - b); n,人的总数
if(a>n || b>n || c>n) cout << -1 << endl;// a or b or c > n,输出-1;
else if(b != a + d) cout << -1 << endl;// 如果a 与 b 在 n 中不是相对而坐的,输出-1;
else {
if(c <= d) cout << c+d << endl;
else cout << c-d << endl;
}
}
return 0;
}
C. Infinity Table
题意:
有一个排列奇怪的表,求 k 在该表中的坐标(x,y)
思路:
找规律,可以用两个一位数组 h[ ]、s[ ] 绘出表的 第一排 和 第一列
每 i 排或每 i 列至多有 i 个数。列,递增;排,递减
- 绘制表边(即第一排和第一列)
- 特判 k == 1
- 找出 k 在第 p 排 或 第 p 列
- 判断 k 在 排【k <= (h[p]+p-1)】 还是 列 ,输出(k-h[p]+1, p) or (p, s[p]-k+1)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 32000;// 1e9 在 第 31623排or列
ll h[N], s[N];// long long 防int炸
void init()
{
h[1] = 1; s[1] = 1;
int x = 1, y = 3;
for(int i=2; i<N; i++) {
h[i] = h[i-1] + x; x += 2;
s[i] = s[i-1] + y; y += 2;
}
}
int main()
{
init();// 绘出 表边(即第一排和第一列)
int t; cin >> t;
while(t--) {
int k; cin >> k;
if(k == 1) {// 特判
printf("1 1\n");
continue;
}
int x, y, p=1;// 坐标(x, y) , 第 p 列or排
for(int i=2; ; i++) {
if(k >= h[i] && k <= s[i]) {
p = i;
break;
}
}
if(k <= (h[p]+p-1)) x = k-h[p]+1, y = p;
else x = p, y = s[p]-k+1;
printf("%d %d\n",x, y);
}
return 0;
}
D.Make a Power of Two
题意:
给一个 n,每次操作 可以删除其中一位数字 或 在末尾加上一位数字
求变为 2的k次方 的最小的操作步数ans(k为任意正整数)
思路:
这题我原本是不会的,看了别人的题解,此处借鉴,下附链接。
- 先考虑数据范围,n最大是1e9,则对每个数的最大操作次数是18次(9次删除9次添加),所以打一个1e18的的2的k次方表
- 考虑贪心策略,对于字符串a和b,将a编辑到b可以在a串中找最长的b串并记录,a串中没有找到的b串剩余部分长度则是最后要在末位加的长度
- 用两个指针p1,p2分别指向a,b 当a[p1] == b[p2]时,记录相同字符长度,即cnt++
- 最终编辑距离 == a串删除的长度 + b串在末位添加的长度 (ans = l1 - cnt + l2 - cnt)
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
// 原作者用 a[] 存了 2的0~108次方,就…就很牛
string a2[] = { "1","2","4","8","16","32","64","128","256","512","1024","2048","4096","8192","16384","32768","65536","131072","262144","524288","1048576","2097152","4194304","8388608","16777216","33554432","67108864","134217728","268435456","536870912","1073741824","2147483648","4294967296","8589934592","17179869184","34359738368","68719476736","137438953472","274877906944","549755813888","1099511627776","2199023255552","4398046511104","8796093022208","17592186044416","35184372088832","70368744177664","140737488355328","281474976710656","562949953421312","1125899906842624","2251799813685248","4503599627370496","9007199254740992","18014398509481984","36028797018963968","72057594037927936","144115188075855872","288230376151711744","576460752303423488","1152921504606846976","2305843009213693952","4611686018427387904","9223372036854775808","18446744073709551616","36893488147419103232","73786976294838206464","147573952589676412928","295147905179352825856","590295810358705651712","1180591620717411303424","2361183241434822606848","4722366482869645213696","9444732965739290427392","18889465931478580854784","37778931862957161709568","75557863725914323419136","151115727451828646838272","302231454903657293676544","604462909807314587353088","1208925819614629174706176","2417851639229258349412352","4835703278458516698824704","9671406556917033397649408","19342813113834066795298816","38685626227668133590597632","77371252455336267181195264","154742504910672534362390528","309485009821345068724781056","618970019642690137449562112","1237940039285380274899124224","2475880078570760549798248448","4951760157141521099596496896","9903520314283042199192993792","19807040628566084398385987584","39614081257132168796771975168","79228162514264337593543950336","158456325028528675187087900672","316912650057057350374175801344","633825300114114700748351602688","1267650600228229401496703205376","2535301200456458802993406410752","5070602400912917605986812821504","10141204801825835211973625643008","20282409603651670423947251286016","40564819207303340847894502572032","81129638414606681695789005144064","162259276829213363391578010288128","324518553658426726783156020576256" };
string a[64];// long long类型可以开到2的0~62次方
void init()
{
ll p = 1;
for(int i=0; i<63; i++) {
a[i] = to_string(p);// 将数转换为字符串的形式
p *= 2;
}
}
int main()
{
init();// 初始化 2的幂次方
int t; cin >> t;
while(t--) {
string s; cin >> s;
int ans = INT_MAX;// 输出结果
for(int k=0; a[k].size(); k++) {
int cnt = 0;// s[p1] 与 a[k].[p2] 相同的个数(下标不对应,仅是遍历s[p1])
int l1 = s.size(), l2 = a[k].size();
int p1=0, p2=0;// 遍历用的两个指针
while(p1 < l1 && p2 < l2) {
if(s[p1] == a[k][p2]) {
p2++; cnt++;
}
p1++;
}
ans = min(ans, l1-cnt + l2-cnt);// 取最小操作数
}
cout << ans << endl;
}
return 0;
}