思路:有三种情况
- 有3种不同的数,如果mid*2=min+max,则成立
- 有2或1种不同的数,那么成立
- 数超过3种,不成立
把不同的数记录在数组a种,每次读入数先判断有没有这个数(用stl find函数),维护数组的index,如果index>4,则意味着有了3种以上不同的数,那么结束。
#include <iostream>
#include <algorithm>
#define ll ll
using namespace std;
ll a[10005];
int main()
{
int t; cin >> t;
while (t--)
{
bool flag = false;
int n, index = 1; cin >> n;
for (int i = 1; i <= n; i++)
{
ll temp; cin >> temp;
if (find(a + 1, a + index, temp) == a + index) a[index++] = temp;
if (index > 4)
{
cout << "NO\n";
flag = true;
for (int j = i + 1; j <= n; j++) cin >> a[j];
break;
}
}
if (flag) continue;
sort(a + 1, a + 4);
if (index <= 3 || 2 * a[2] == a[1] + a[3]) cout << "YES\n";
else cout << "NO\n";
}
}
Problem B-HRZ学英语
Description
瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想 到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想, 这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字 符’?’,特殊字符’?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字 母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现 的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果 不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮 他解决这个问题,报酬是可以帮你打守望先锋。 说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二 个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排 在前。例如
AB??EFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ABDCEFGHIJKLMNOPQRSTUVWXYZ
1
2
上面两种填法,都可以构成26个字母,但是我们要求字典序最小,只能取前者。 注意,题目要求的是 第一个出现的,字典序最小的!
Input
输入只有一行,一个符合题目描述的字符串。
Output
输出只有一行,如果存在这样的子串,请输出,否则输出-1
Samples
Input
ABC??FGHIJK???OPQR?TUVWXY?
Onput
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Input
AABCDEFGHIJKLMNOPQRSTUVW??M
Output
-1
Note
思路:类似于尺取法,维护一个窗口,没有重复的字母。如果遇到?,continue,遇到字母,判断窗口内是否存在,判断方法是定义一个bool数组exist,如果存在,则调整窗口左端位置,字母所在位置记录在数组position种,调整到重复字母只有一个。如果窗口大小为26,则停止。输出时,如果遇到?,则检索exist数组,输出字典序最小的且不存在的,之后把该元素设置为true.
#include<string>
#include<iostream>
#define ll long long
using namespace std;
bool exist[26] = { false };
ll position[26];
int main()
{
string str;cin >> str;
ll l = 0, r = -1, size = str.size();
for (ll i = 0; i < size; i++)
{
if (str[i] == '?')
{
if ((i - l + 1) == 26)
{
r = i;
break;
}
else continue;
}
if (exist[str[i] - 'A'] == true)
{
for (ll m = l; m < position[str[i] - 'A']; m++)
exist[str[m] - 'A'] = false;
l = position[str[i] - 'A'] + 1;
position[str[i] - 'A'] = i;
}
else
{
exist[str[i] - 'A'] = true;
position[str[i] - 'A'] = i;
}
if ((i - l + 1) == 26)
{
r = i;
break;
}
}
if (r == -1)
{
cout << -1;
}
else
{
int now = 0;
for (ll m = l; m <= r; m++)
{
if (str[m] != '?') cout << str[m];
else
{
for (int p = now; p < 26; p++)
{
if (exist[p] == false)
{
cout << (char)(p + 'A');
now = p + 1;
break;
}
}
}
}
}
}
C-咕咕东的奇妙序列
Description
咕咕东 正在上可怕的复变函数,但对于稳拿A Plus的 咕咕东 来说,她早已不再听课,此时她在睡梦中 突然想到了一个奇怪的无限序列:112123123412345 …这个序列由连续正整数组成的若干部分构成,其 中第一部分包含1至1之间的所有数字,第二部分包含1至2之间的所有数字,第三部分包含1至3之间的所 有数字,第i部分总是包含1至i之间的所有数字。所以,这个序列的前56项会是 11212312341234512345612345671234567812345678912345678910,其中第1项是1,第3项是2,第20项是 5,第38项是2,第56项是0。咕咕东 现在想知道第 k 项数字是多少!但是她睡醒之后发现老师讲的东西 已经听不懂了,因此她把这个任务交给了你。
Input
输入由多行组成。 第一行一个整数q表示有q组询问(1<=q<=500)
接下来第i+1行表示第i个输入ki,表示询问第ki项数字。 1<=ki<=10^18
Output
输出包含q行
第i行输出对询问ki的输出结果。
Sample Input
5
1
3
20
38
56
1
2
3
4
5
Sample Onput
1
2
5
2
0
1
2
3
4
Note
思路:举个例子,输入数据记为i,就是位置,如果i == 67,那结果就是0
(1 12 123 1234 12345 123456 1234567 12345678 123456789 ) (12345678910
1234567981~~0~~ 11 )👈就是这个0
空格分开的我称之为大区间,先确定大区间中最大数的位数(就是收在那个括号中,括号中的大区间最大位数相同),最大数位数相同的大区间的长度为等差序列,比如对于上面例子来说序列为:
1 2 3 4 5 6 7 8 9 (一位)
11 13 15 17…(二位)
这样的话用等差求和公式来计算卡区间。
这样定位到了二位的大区间,i-=preSum,就是减去一位大区间的总长度,问题变成从
12345678910 1234567891011 …
中找第i位,计算得i == 67-45=22。
接下来确定具体在哪个大区间,在一个括号中的大区间的长度符合等差序列,方便求和。采用二分法来找到大区间——否则会超时——二分的基准是第x个大区间,初始时l == 1,r == 括号中总区间数cnt,cnt在上面步骤中已经求出,比较 i 与 第一个大区间到mid所在大区间的总位数 的大小。
在例子中总长度的序列为:11 11+13, 11+13+15…所以i == 22在11+13的大区间里。i-=preSum,计算得i==11,问题转化为在
1234567891011中找到第11位
先确定i在所在的数字是第几位。。。懒得说了
#include <iostream>
#include <string>
#define ll long long
using namespace std;
ll func(ll i)
{
ll sum = 0, preSum = 0, index = 0, cnt = 9, a = 1, b = 1;
while (sum < i)
{
preSum = sum;
sum += (cnt * b + cnt * (cnt - 1) * a / 2);
b += cnt * a + 1;
cnt *= 10, a++;
}
ll rest = i - preSum;
a--, cnt /= 10;
b -= cnt * a + 1;
ll max = b + (cnt - 1) * a;
ll r = cnt;
ll l = 1;
ll mid = (r + l) / 2;
while (l < r)
{
if (rest < mid * b + mid * (mid - 1) * a / 2)
{
r = mid - 1;
mid = (l + r) / 2;
continue;
}
else if (rest > mid * b + mid * (mid - 1) * a / 2)
{
l = mid + 1;
mid = (l + r) / 2;
continue;
}
else break;
}
if (rest > mid* b + mid * (mid - 1) * a / 2) mid++;
rest -= b * (mid - 1) + (mid - 1) * (mid - 2) * a / 2;
sum = preSum = cnt = 0;
cnt = 9;
/*确定位数*/
b = 1;//位数
while (sum < rest)
{
preSum = sum;
sum += cnt * b;
cnt *= 10;
b++;
}
rest -= preSum;
b--;
ll k = pow(10, b - 1);
a = (rest - 1) / b;
ll number = k + a;
rest %= b;
string s = to_string(number);
rest = rest == 0 ? b : rest;
ll p = log10(number);
ll o = pow(10, p + 2 - rest);
ll e = pow(10, p + 1 - rest);
return number % o / e;
}
int main()
{
int q; cin >> q;
while (q--)
{
ll i; cin >> i;
cout << func(i) << endl;
}
}
反思:代码写的挺乱的,因为一直在纠结给变量取名字的问题。。。