A - HRZ的序列
问题描述
现有一个长度为n的序列,问是否存在这样一个数,使得序列中一些数加上这个数 ,一些数减去这个数,一些数不变,使得整个序列中所有的数相等(其中对于序列中的每个位置上的数字,至多只能执行一次加运算或减运算或是对该位置不进行任何操作)。
Input
输入第一行是一个正整数 t, 表示数据组数。接下来对于每组数据,输入的第一个正整数n表示a序列的长度,随后一行有n个整数,表示a序列 。
Output
输出共包含t行,每组数据输出一行。对于每组数据,如果存在这样的K,输出"YES",否则输出“NO”。(输出不包含引号)
Example
Input
25
1 2 3 4 5
5
1 2 3 4 5
Output
NO
NO
解题思路
因为要使这个序列的数都相等, 因此最多只能有三个数不相等。所以使用set容器, 将整个a序列存入set< long long int >类型
(一定要注意数据范围!!!!)
的数组b中,然后查看数组b的size即可。 如果size<=2,那么一定存在所要求的数字;如果size==3,只要满足三个数字的平均值等于b[2],那么就存在这样一个数字,否则不存在;如果 size>=4, 那么一定不存在。
代码
#include <iostream>
#include <cmath>
#include <set>
#include <string.h>
#include <stdio.h>
using namespace std;
long long int a[10010], c[3], min1, max1;
set<long long int> p, q;
int main()
{
int m, n, status, count, s, m1;
scanf("%d", &n);
for(int i=0;i<n;i++)
{
status = 0, s = 0;
scanf("%d", &count);
p.clear(), q.clear();
for(int i=0;i<count;i++)
{
scanf("%lld",&a[i]);
p.insert(a[i]);
}
set<long long int> ::iterator it = p.begin();
if(p.size()==3)
{
while(it!=p.end())
{
c[s++] = *it;
it++;
}
if(c[0]+c[2]==2*c[1])
status = 1;
}
if(status||p.size()<=2)
printf("YES\n");
else
printf("NO\n");
}
return 0;
}
B - HRZ学英语
问题描述
现在给定一个字符串,字符串中包括26个大写字母和特殊字符 ‘?’ ,特殊字符 ‘?’ 可以代表任何一个大写字母。问是否存在一个位置连续的且由26个大写字母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果不存在,就输出-1!
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排在前。例如
AB??EFGHIJKLMNOPQRSTUVWXYZ
ABCDEFGHIJKLMNOPQRSTUVWXYZ
ABDCEFGHIJKLMNOPQRSTUVWXYZ
上面两种填法,都可以构成26个字母,但是我们要求字典序最小,只能取前者。
注意,题目要求的是 第一个出现的,字典序最小的!
Input
输入只有一行,一个符合题目描述的字符串。
Output
输出只有一行,如果存在这样的子串,请输出,否则输出-1
Example
Input1
ABC??FGHIJK???OPQR?TUVWXY?
Output1
ABCDEFGHIJKLMNOPQRSTUVWXYZ
Input2
AABCDEFGHIJKLMNOPQRSTUVW??M
Output2
-1
解题思路
这道题和之前写过的窗口移动比较相似,但是窗口大小是固定的,因此更好处理。所以从i=25开始遍历字符串即可。至于如何判断数组中的26个字母是否各不相同, 则需要开辟一个长度为26的数组来进行统计,也可以通过这个数组来找出 ‘?’ 对应的字母。然后将字符串中 ‘?’ 替换为指定的字母即可。如果替换后得到的字符串中各不相同的字母数等于26, 就输出该字符串;如果直到遍历的字符串尾都找不到符合条件的字符串就输出-1.
代码
#include <iostream>
#include <string.h>
#include <string>
using namespace std;
char a[26];
int main()
{
string s;
cin>>s;
int l = 0, r = 25, m = 0, length;
for(int i=25;i<s.size();i++)
{
m = 0;
length = l+26;
int b[26] = {0};
for(int j=l;j<length;j++)
{
if(s[j]!='?')
{
a[j-l] = s[j];
b[s[j]-65] = 1;
}
}
for(int i=l;i<length;i++)
{
if(s[i]=='?')
{
for(int j=0;j<26;j++)
if(b[j]==0)
{
a[i-l] = j + 65, b[j] = 1;
break;
}
}
}
l++;
int sum = 0;
for(int i=0;i<26;i++)
{
if(b[i]==1)
sum++;
}
if(sum==26)
{
for(int i=0;i<26;i++)
printf("%c", a[i]);
return 0;
}
}
printf("-1");
return 0;
}
C - 咕咕东的奇妙序列
问题描述
112123123412345 …这个序列由连续正整数组成的若干部分构成,其中第一部分包含1至1之间的所有数字,第二部分包含1至2之间的所有数字,第三部分包含1至3之间的所有数字,第i部分总是包含1至i之间的所有数字,11212312341234512345612345671234567812345678912345678910,其中第1项是1,第3项是2,第20项是5,第38项是2,第56项是0。现在想知道第 k 项数字是多少。
Input
输入由多行组成。
第一行一个整数q表示有q组询问(1<=q<=500)
接下来第i+1行表示第i个输入ki,表示询问第ki项数字
Output
输出包含q行
第i行输出对询问ki的输出结果
Example
Input
5
1
3
20
38
56
Output
1
2
5
2
0
解题思路
因为数据范围比较大,如果一层一层的找想要查找的数字位于第几层,那么会超时。因此,需要二分地进行查找。因此问题关键就在于如何计算当前层级包含的数字总数。具体公式就不详细介绍(从1-9算起,依次计算10-99, 100-999的层级数字数之和。每一级的运算过程是先计算出位数相同的数字的数字数,比如说层级为2时,即当前数字最大为99,计算出层为10-99(他们中两位数的个数为1-90)中的数字之和再乘以2,再加上更高层级中所有位数为2的数字数,由此即可计算出二位数的所有数字个数,以此类推,大致过程就是这样)。
至于每一层的中数字个数,计算过程与上述类似,就不在介绍。然后运用二分的思想即可更快的求出当前层级和具体数字,输出特定的数字即可。
代码
#include <iostream>
#include <stdio.h>
#include <cmath>
using namespace std;
long long int n, m, level, num, s, r, l;
long long int sum(long long int x)
{
return (x + 1) * x / 2;
}
long long int getsum1(long long int x)
{
long long int ans = 0, i = 1, j = 1;
for (i = 1, j = 1; j * 10 <= x; i++, j *= 10)
ans = ans + i * sum(j * 9) + i * j * 9 * (x - j * 10 + 1);
return ans + i * sum(x - j + 1);
}
long long int getsum2 (long long int x)
{
long long int ans=0, i=1, j=1;
for (i=1, j=1 ; j*10<=x; i++,j*=10 ) {
ans += i*j*9;
}
return ans + i*(x-j+1);
}
int main()
{
scanf("%lld", &n);
for (int i = 0; i < n; i++)
{
scanf("%lld", &m);
l = 0, r = 1e9;
while (l <= r)
{
long long int mid = (l + r) / 2;
if (getsum1(mid) < m)
{
l = mid + 1;
level = mid;
}
else
r = mid - 1;
}
m = m - getsum1(level++);
l = 0, r = level;
while (l <= r)
{
long long int mid = (l + r) / 2;
if (getsum2(mid) < m)
{
l = mid + 1;
num = mid;
}
else
r = mid - 1;
}
m = m - getsum2(num++);
int a[30] = {0}, j = 0;
while (num != 0)
{
a[j++] = num % 10;
num = num / 10;
}
printf("%d\n", a[j - m]);
}
return 0;
}