HRZ的序列
解题过程
之前在查set的资料的时候看到过这个题,就是如果存在k则这个数据的不同的数必须在三个或三个以下,如果是三个一下肯定存在k,如果是三个数则需要是一个等差数列,遇到这个题就很开心,结果一个点也没过。因为是多组数据,set没有清空,根本没有记住教训的样子。
#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
#include <stdio.h>
#include <queue>
#include<utility>
#include<set>
using namespace std;
//int a[100050];
long long a2[3];
int main(int argc, char** argv) {
int t,c=0;
cin>>t;
while(t--)
{if(c!=0)
cout<<endl;
c++;
long long n,num;
cin>>n;set<long long> a;
for(int i=0;i<n;i++)
{ cin>>num;
a.insert(num);
}
if(a.size()>3)
{cout<<"NO";
}
else
{ if(a.size()<=2)
cout<<"YES";
else if(a.size()==3)
{int u=0;
set<long long>::iterator it1;
for(it1=a.begin();it1!=a.end();it1++)
{a2[u]=*it1;
u++;
}
sort(a2,a2+3);
if(2*a2[1]==a2[0]+a2[2])
cout<<"YES";
else
cout<<"NO";
}
}
}
return 0;
}
HRZ 学英语
解题过程
第一反应是尺取,最后也是这样做的。用一个26长的框进行选择,记录26个字母的存在状况到a数组和框中序列到put数组,如果出现重复字母则向前移动,如果26个字母均不重复则输出。输出时出现?则查找框中不存在的字母输出并标记该字母,因为字母按字典序排序所以序列必定是字典序最小。
模拟的时候只过了4个点,因为没有清空两个数组,当时想起了过但是一瞬间就忘了可能是因为写代码很慢所以在着急吧,同样的错误犯了两次。补题的时候清空了数组但是在第八个点出现错误,发现是字母数的原因,如果是在26位重复会检测到重复并break但是计数是26个就会进入输出环节,加了对是否是break结束的判断然后就过了,有点可惜的一道题。
#include <iostream>
#include <stack>
#include <cmath>
#include <cstdlib>
#include<algorithm>
#include<cstring>
#include<vector>
#include <stdio.h>
#include <queue>
#include<utility>
using namespace std;
int a[27]={0};
char put[27];
int chang (char p)
{
if(p!='?')
return p-65;
else
return 26;
}
void putt()
{ char c;
for(int i=0;i<26;i++)
{ if(put[i]!='?')
cout<<put[i];
else if(put[i]=='?')
{ for(int j=0;j<26;j++)
if(a[j]==0)
{c=j+65;
cout<<c;
a[j]=1;
break;
}
}
}
}
int main(int argc, char** argv) {
long long n ,fnum=0,ans=0,num=0,flag=0;
string s;
cin>>s;
if(s.length()<26)
cout<<-1;
else
{
long long l=0,r=25,len=s.length();
while(r<len)
{
for(long long i=l;i<=r;i++)
{ put[num]=s[i];
num++;
if(s[i]=='?')
{fnum++;
}
else
{if(a[chang(s[i])]==1)
{ flag=3;
break;
}
else
a[chang(s[i])]=1;
}
}
if(num==26&&flag!=3)
{putt();
flag=1;
break;
}
l++;
r++;
num=0;
flag=0;
memset(a,0,sizeof(a));
memset(put,0,sizeof(put));
}
if(flag!=1)
cout<<-1;
}
return 0;
}
咕咕东的奇妙序列
解题过程
模拟的时候就剩一丢丢时间了于是就把题干的数据用上过了3个点,好像后面的有些数据也可以暴力但是当时没有时间了……也有想到过等差数列的求和公式但是没想出来怎么做,二分就是根本没有想到。平时作业一直抄模板和遇到困难问同学的报应。
序列的每一部分都是首项为1公差为1的等差数列,所在的位置就是对应的数列和(Sn)在该部分的项数(n),序列的每一部分的长度也是一个等差数列,因为是从题目来看是将数字拆封成个位数的,所以每次位数上升划为一段,0-9是公差为1,10-99是公差为2以此类推,在部分中确定数的位置也要这样。数很多要用二分查找,先查找数在哪一个分段,再寻找这个数在该分段对应的数。
#include <iostream>
#include <cstdlib>
#include <stack>
#include <cmath>
#include <algorithm>
#include <string>
#include <stack>
#include<set>
using namespace std;
long long ans=0,mid=0;
long long where(long long kk)
{
long long a0=0,d=0,n=0,sum=0,u=1,an=0;
while(true)
{ d++;
u=u*10;
n=u-u/10;
if(kk>u-1)
{ a0=an+d;
an=a0+(n-1)*d;
sum=sum+(a0+an)*n/2;
}
else
{ n=kk-u/10+1;
a0=an+d;
an=a0+(n-1)*d;
sum=sum+(a0+an)*n/2;
return sum;
}
}
}
long long where2(long long kk)
{
long long a0=0,d=0,n=0,sum=0,u=1,an=0;
while(true)
{ d++;
u=u*10;
n=u-u/10;
if(kk>u-1)
{
a0=an+d;
an=a0+(n-1)*d;
}
else
{ n=kk-u/10+1;
a0=an+d;
an=a0+(n-1)*d;
return an;
}
}
}
void func(long long l,long long r,long long mid ,long long k)
{ while(l<=r)
{ mid=(l+r)/2;
if(where(mid)>=k)
{r=mid-1;
ans=mid;
}
else
l=mid+1;
}
}
void func2(long long l,long long r,long long mid ,long long k)
{ while(l<=r)
{ mid=(l+r)/2;
if(where2(mid)>=k)
{r=mid-1;
ans=mid;
}
else
l=mid+1;
}
}
int main(int argc, char** argv) {
long long q;
string s;
cin>>q;
while(q--)
{long long k;
cin>>k;
long long l=0,r=1000000000;
ans=0,mid=0;
func(l,r,mid,k);
k=k-where(ans-1);
r=ans+1;
l=0;
func2(l,r,mid,k);
k=k-where2(ans-1);
s=to_string(ans);
cout<<s[k-1];
if(q!=0)
cout<<endl;
}
return 0;
}