题目一 HRZ 的序列
题目描述
相较于咕咕东,瑞神是个起早贪黑的好孩子,今天早上瑞神起得很早,刷B站时看到了一个序列 ,他对这个序列产生了浓厚的兴趣,他好奇是否存在一个数 ,使得一些数加上 ,一些数减去 ,一些数不变,使得整个序列中所有的数相等,其中对于序列中的每个位置上的数字,至多只能执行一次加运算或减运算或是对该位置不进行任何操作。由于瑞神只会刷B站,所以他把这个问题交给了你!
input
输入第一行是一个正整数 表示数据组数。 接下来对于每组数据,输入的第一个正整数 表示序列的长度,随后一行有 个整数,表示序列 。
output
输出共包含 行,每组数据输出一行。对于每组数据,如果存在这样的K,输出"YES",否则出“NO”。(输出不包含引号)
example
input 1
2
5
1 2 3 4 5
5
1 2 3 4 5
output 1
NO
NO
做法与思路
如果k存在的话,则只有两种情况,一种是a-k=b,另一种是a-k-b-k,所以我们可以选出这组数据中的最小值和最大值,令k1=b-a,k2=(b-a)/2,然后先对k1进行检验,如果k1可行则输出YES;不可行则再对k2进行检验,可行则输出YES,不可行输出NO。
代码
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
long long a[20000];
int main(int argc, char** argv) {
int ci;
cin>>ci;
for(int cci=0;cci<ci;cci++)
{
int judge2=0;
int n;
cin>>n;
long long minn;
long long maxx;
cin>>a[0];
minn=a[0];
maxx=a[0];
for(int i=1;i<n;i++)
{
cin>>a[i];
if(a[i]>maxx) maxx=a[i];
if(a[i]<minn) minn=a[i];
}
long long k1=maxx-minn;
long long k2=(maxx-minn)/2;
bool judge=0;
for(int i=0;i<n;i++)
{
if((a[i]+k1!=maxx)&&(a[i]!=maxx))
{
judge=1;
break;
}
}
if(judge==0)
{
cout<<"YES"<<endl;
continue;
}
judge=0;
for(int i=0;i<n;i++)
{
if((a[i]+k2!=maxx-k2)&&(a[i]!=maxx-k2)&&(a[i]-k2!=maxx-k2))
{
judge=1;
break;
}
}
if(judge==0)
{
cout<<"YES"<<endl;
continue;
}
cout<<"NO"<<endl;
}
return 0;
}
题目二 HRZ学英语
题目描述
瑞神今年大三了,他在寒假学会了英文的26个字母,所以他很兴奋!于是他让他的朋友TT考考他,TT想到了一个考瑞神的好问题:给定一个字符串,从里面寻找连续的26个大写字母并输出!但是转念一想,这样太便宜瑞神了,所以他加大了难度:现在给定一个字符串,字符串中包括26个大写字母和特殊字符’?’,特殊字符’?'可以代表任何一个大写字母。现在TT问你是否存在一个位置连续的且由26个大写字母组成的子串,在这个子串中每个字母出现且仅出现一次,如果存在,请输出从左侧算起的第一个出现的符合要求的子串,并且要求,如果有多组解同时符合位置最靠左,则输出字典序最小的那个解!如果不存在,输出-1! 这下HRZ蒙圈了,他刚学会26个字母,这对他来说太难了,所以他来求助你,请你帮他解决这个问题,报酬是可以帮你打守望先锋。
说明:字典序 先按照第一个字母,以 A、B、C……Z 的顺序排列;如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,SIGH 和 SIGHT),那么把短者排在前。
input
输入只有一行,一个符合题目描述的字符串。
output
输出只有一行,如果存在这样的子串,请输出,否则输出-1。
example
input 1
ABC??FGHIJK???OPQR?TUVWXY?
output 1
ABCDEFGHIJKLMNOPQRSTUVWXYZ
做法与思路
由于是连续区间所以第一反应就是尺取法。
尺取法的关键是判断什么情况下为“满足”。
对于该题,首先要保证区间长度为26,然后统计区间内A~Z的个数,如果存在字母个数大于1则不满足。然后把各个字母的个数加起来再加?的个数,如果总数为26,则满足条件。否则,让右端点向右移动一位。如果区间长度大于26,则让左端点向右移动一位,如果直到结束都没有满足条件则输出-1.
这里再提一下输出,因为要输出字典序最小,所以我们应该遍历这组字符串,遇到?时,按顺序遍历A~Z,如果字母的个数为0,则我们让这个字符变为该字母,同时把该字母的个数变成1即可。
代码
#include <iostream>
#include <cstring>
#include <map>
using namespace std;
map<char,int> a;
int numble;
int main(int argc, char** argv) {
string s;
cin>>s;
int l=0,r=0;
a[s[0]]++;
while((l<=r)&&(r<s.length()))
{
if(r-l>25)
{
a[s[l]]--;
l++;
}
else if(r-l==25)
{
int sum=0;
for(char i='A';i!='[';i++)
{
int tem=a[i];
if(tem>1) break;
sum+=tem;
}
sum+=a['?'];
if(sum==26)
{
for(int i=l;i<=r;i++)
{
if(s[i]=='?')
{
for(char j='A';j!='[';j++)
{
if(a[j]==0)
{
cout<<j;
a[j]=1;
break;
}
}
}
else cout<<s[i];
}
return 0;
}
else
{
r++;
a[s[r]]++;
}
}
else
{
r++;
a[s[r]]++;
}
}
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 项数字是多少!但是她睡醒之后发现老师讲的东西已经听不懂了,因此她把这个任务交给了你。
input
输入由多行组成。
第一行一个整数q表示有q组询问。(1<=q<=500)
接下来第i+1行表示第i个输入 ,表示询问第 项数字。 (1<=ki<=1e18)
output
输出包含q行
第i行输出对询问 的输出结果 。
example
input 1
513
20
38
56
output 1
1
2
5
2
0
做法与思路
事实上这个题更像是一道数学寻找规律题。
数据量达到了1e18,所以穷举过去肯定是不行的,必须要缩小查找的范围。
通过观察我们发现
1
12
123
…
123456789
12345678910
1234567891011
…
1234567891011…99
1234567891011…99100
…
1到9时每行增长1,10到99时每行增长2,100到999时每行增长3。
这样子我们可以把数据划分成一个个梯形,先确定所要求的数据在哪个梯形中,再确定想要求的数据在该梯形的第几行中,再在该行中确定具体位置。这样就大大缩短了查找所需要的时间。
但值得注意的是,虽然梯形的数目较少,但某个梯形中的行数可能很多,如123…10000到123…99999这个梯形中整整有100000条,如果按顺序查找该数字再第几行中会超时,所以再确定行数时应该使用二分查找。
代码
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;
long long sum[10000];
const long long maxx=pow(10,18);
long long shang[10000];
long long xia[10000];
long long gao[10000];
int main(int argc, char** argv) {
long long cengshu=0;//记录层数
while(sum[cengshu]<maxx)
{
cengshu++;
shang[cengshu]=xia[cengshu-1]+cengshu;
gao[cengshu]=pow(10,cengshu)-pow(10,cengshu-1);
xia[cengshu]=shang[cengshu]+(gao[cengshu]-1)*cengshu;
sum[cengshu]=sum[cengshu-1]+(xia[cengshu]+shang[cengshu])*gao[cengshu]/2;
//cout<<sum[cengshu]<<endl;
}
int nt;
cin>>nt;
for(int ci=0;ci<nt;ci++)
{
long long t;
cin>>t;
int i=0;
while(t>sum[i])
{
i++;//确定在哪个梯形
}
long long target=t-sum[i-1];
long long l=1;
long long r=gao[i];
long long mid=(r+1)/2;
long long judge=mid*shang[i]+mid*(mid-1)/2*i;
while(l<r)
{
//cout<<1<<endl;
mid=(r+l)/2;
judge=mid*shang[i]+mid*(mid-1)/2*i;
if(target>judge)
{
l=mid+1;
}
else if(target<judge)
{
r=mid;
}
else
{
l=mid;
r=mid;
break;
}
}//r即为所在梯形中的条数
// cout<<"在第"<<i<<"个梯形的第"<<r<<"条"<<endl;
target-=(r-1)*shang[i]+(r-1)*(r-2)/2*i;//在该条中的位置
// cout<<"在该条中是第"<<target<<"个数"<<endl;
i=0;
while(target>xia[i])
{
i++;
}//i表示该数字所属大数字的位数,如56是10这个数字的第二个数,i则为2
// cout<<"所在整数的位数为"<<i<<endl;
target=(target-xia[i-1]);
long long shu_zi_de_ci_xu=(target-1)/i;
// cout<<"在位数中的位置为"<<shu_zi_de_ci_xu<<endl;
long long shengyu=(target-1)%i;
// cout<<"是第"<<shengyu<<"位"<<endl;
long long shuzi=pow(10,i-1)+shu_zi_de_ci_xu;
// cout<<"该数是"<<shuzi<<endl;
char shu[10000];
itoa(shuzi,shu,10);
cout<<shu[shengyu]<<endl;
}
return 0;
}