A - HRZ 的序列
相较于咕咕东,瑞神是个起早贪黑的好孩子,今天早上瑞神起得很早,刷B站时看到了一个序列 ,他对这个序列产生了浓厚的兴趣,他好奇是否存在一个数 ,使得一些数加上 ,一些数减去 ,一些数不变,使得整个序列中所有的数相等,其中对于序列中的每个位置上的数字,至多只能执行一次加运算或减运算或是对该位置不进行任何操作。由于瑞神只会刷B站,所以他把这个问题交给了你!
输入格式
输入第一行是一个正整数 表示数据组数。 接下来对于每组数据,输入的第一个正整数 表示序列的长度,随后一行有 个整数,表示序列 。
输出格式
输出共包含 行,每组数据输出一行。对于每组数据,如果存在这样的K,输出"YES",否则出“NO”。(输出不包含引号)
样例输入
2
5
1 2 3 4 5
5
1 2 3 4 5
样例输出
NO
NO
思路
对于每组数据,如果这组数只由1种或2种数字组成,那么K就是两者之间的差,如果由大于3种的数组成,那么一定可以不存在这样的K,而对于由3种数字组成的数,如果中位数不是最值的平均数的话,也不存在这样的K,所以关键只需要判断平均数即可。
代码
#include<iostream>
#include<math.h>
using namespace std;
bool pd(long long a,long long b,long long c){
// if((a==b)||(a==c)||(b==c)) return false;
long long ma = max(max(a,b),c);
long long mi = min(min(a,b),c);
long long d = ceil((ma+mi)/2);
if((d==a)||(d==b)||(d==c)) return true;//这里是重点
return false;
}
int main(){
// freopen("in1.txt","r",stdin);
int z;
cin>>z;
int n;
while(z){
z--;
long long a=0,b=0,c=0;
long long tmp;
bool v[4];
bool ans = true;
for(int i=0;i<4;i++){
v[i] = 0;
}
cin>>n;
if(n<=2){
while(n){
cin>>tmp;
n--;
}
cout<<"YES"<<endl;
}
else{
scanf("%lld",&a);
v[1] = true;
n--;
while(n){
n--;
scanf("%lld",&tmp);
if(tmp!=a){
if(v[2]&&tmp!=b){
if(v[3]&&tmp!=c){
ans = false;
}
else if(!v[3]){
v[3] = true;
c = tmp;
}
}
else if(!v[2]){
v[2] = true;
b = tmp;
}
}
}
if(!v[2]){
cout<<"YES"<<endl;
}
else if(!v[3]){
cout<<"YES"<<endl;
}
else if((ans&&pd(a,b,c))) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
return 0;
}
问题
在对long long 型数据进行处理的时候,总是产生精度上的问题,所以最好不要使用double和long long之间进行相互转换,而是只使用long long 型数据进行判断。
B - HRZ 学英语
瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想,这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字符'?',特殊字符'?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮他解决这个问题,报酬是可以帮你打守望先锋。
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排在前。
输入格式
输入只有一行,一个符合题目描述的字符串。
输出格式
输出只有一行,如果存在这样的子串,请输出,否则输出-1。
样例输入1
ABC??FGHIJK???OPQR?TUVWXY?
样例输出1
ABCDEFGHIJKLMNOPQRSTUVWXYZ
样例输入2
AABCDEFGHIJKLMNOPQRSTUVW??M
样例输出2
-1
思路
从起点移动大小为26的窗口,判断内部的数据是否符合要求,如果符合要求的话,对其中的?字符进行按照字典序更换即可。
关于字典序
字典序就是按照在英文字母表中的出现顺序代表队次序。题目中的字典序是要求按照符合要求后,在替换的时候按照整体缺少的字母的字典序进行替换。
代码
#include<iostream>
using namespace std;
string s;
char c[1000000+10];
int num[26];
bool check(int l,int r) {
for(int i=0; i<26; i++) {
num[i] = 0;
}
for(int i=l; i<r; i++) {
if(c[i]=='?') continue;
int index = c[i] - 'A';
num[index]++;
if(num[index]>1) return false;
}
return true;
}
int main() {
// freopen("in2.txt","r",stdin);
cin>>s;
bool ans = false;
// cout<<s<<endl;
for(int i=0; i<s.length(); i++) {
c[i] = s.c_str()[i];
}
int l = 0, r = 26;
while(r<=s.length()) {
if(check(l,r)) {
ans = true;
for(int i=l; i<r; i++) {
if(c[i]=='?') {
for(int j=0; j<26; j++) {
if(num[j]==0) {
num[j]++;
c[i] = 'A'+j;
break;
}
}
}
}
break;
}
else {
l++;
r++;
}
}
if(ans)
for(int i=l; i<r; i++) {
cout<<c[i];
}
else cout<<-1;
return 0;
}
咕咕东的奇妙序列
咕咕东 正在上可怕的复变函数,但对于稳拿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 项数字是多少!但是她睡醒之后发现老师讲的东西已经听不懂了,因此她把这个任务交给了你。
输入格式
输入由多行组成。
第一行一个整数q表示有q组询问。(\(1<=q<=500\))
接下来第i+1行表示第i个输入 ,表示询问第 项数字。 (\(1<=k_i<=10^{18}\))
输出格式
输出包含q行
第i行输出对询问 的输出结果 。
样例输入
513
20
38
56
样例输出
1
2
5
2
0
思路
由于数据量庞大,直接存储这些序列显然是不现实的,所以需要先对这个序列进行观察,发现这些序列可分为n组,而每组序列的个数也可以根据其组数表达出来,所以首先我们可以判断其所在的组数,再判断其在该组的位置即可。
而对于查找其组数和位置可以采用二分的方法。
坑点
对于long long型数据的处理再次出错,可以通过中间数据暂时存储long long,而不是直接在表达式中写含有long long型的数值运算。
代码
#include<iostream>
#include<cmath>
using namespace std;//long long 后尽量不跟算式,将算式暂存起来进行计算。
long long line(long long n){
if(n<=9) return n;
else if(n<=99) return (n-9)*2+9;
else if(n<=999) return (n-99)*3+90*2+9;
else if(n<=9999) return (n-999)*4+900*3+90*2+9;
else if(n<=99999) return (n-9999)*5+9000*4+900*3+90*2+9;
else if(n<=999999) return (n-99999)*6+90000*5+9000*4+900*3+90*2+9;
else if(n<=9999999) return (n-999999)*7+line(999999);
else if(n<=99999999) return (n-9999999)*8+line(9999999);
else if(n<=999999999) return (n-99999999)*9+line(99999999);
// else if(n<=9999999999) return (n-999999999)*10+900000000*9+90000000*8+9000000*7+900000*6+90000*5+9000*4+900*3+90*2+9;
// else if(n<=99999999999) return (n-9999999999)*11+9000000000*10+900000000*9+90000000*8+9000000*7+900000*6+90000*5+9000*4+900*3+90*2+9;
}
int main(){
// freopen("in3.txt","r",stdin);
long long t[15];
t[0] = 0;
for(long long i = 1;i < 10;i++){
long long num = ((line(pow(10,i-1))+line(pow(10,i)-1))*9*pow(10,i-1))/2;
t[i] = t[i-1] + num;
// cout<<t[i]<<endl;
}
int q;
cin>>q;
long long op;
while(q){
q--;
scanf("%lld",&op);
long long zu=0;
for(long long i=1;i<10;i++){
if(op>t[i-1]&&op<=t[i]){
zu = i;
break;
}
}
// cout<<zu<<endl;
long long mid = 0;
long long left = pow(10,zu-1),right = pow(10,zu)-1;
while(left<=right){
mid = (left+right)/2;
long long num = ((line(pow(10,zu-1))+line(mid))*(mid-pow(10,zu-1)+1))/2;
long long su = t[zu-1]+num;
// cout<<su<<endl;
if(su>=op){
right = mid - 1;
}
else {
left = mid + 1;
}
}
// cout<<left<<","<<right<<endl;
long long num = ((line(pow(10,zu-1))+line(left))*(left-pow(10,zu-1)+1))/2;
long long lsu = t[zu-1]+num;
num = ((line(pow(10,zu-1))+line(right))*(right-pow(10,zu-1)+1))/2;
long long rsu = t[zu-1]+num;
// cout<<left<<","<<right<<","<<lsu<<","<<rsu<<endl;
// cout<<rsu<<endl;
long long index = op - rsu;
// cout<<index<<endl;
long long ans = 0;
long long l = 1,r = left;
long long m;
while(l<=r){
m = (l+r)/2;
if(index<line(m)){
r = m - 1;
}
else{
l = m + 1;
}
}
// cout<<r<<","<<l<<endl;
// cout<<line(r)<<","<<index<<endl;
if(index>line(r)){
r = l;
}
long long tmp = line(r-1);
// cout<<r<<","<<tmp<<","<<index<<endl;
long long tindex = index - tmp;
// cout<<tindex<<endl;
long long w = floor(log(r)/log(10))+1;
long long tt = floor(r/pow(10,w-tindex));
ans = tt%10;
cout<<ans<<endl;
}
return 0;
}