做题手感太差。明明全是水题,但是思路就容易卡死,其实有想到正确做法的,但是要么思路没成型,要么就是不知道操作性怎么样没敢试。结果到最后思路偏了卡题卡到最后也就写了一题。听完讲题思路对了直接快速AC。
题意:给一个数字数组,其子串(长度大于等于2)中最大和第二大的数异或的值为幸运数,找所有子串(长度大于等于2)中最大的幸运数。
解:
单调栈处理每个数 左边第一个比自己大的数和右边第一个比自己大的数。对于当前数i,左边第一个比自己大的数和自己异或构成一个幸运数,右边第一个比自己大的数和自己构成一个幸运数。每个数得到至多两个幸运数,所有幸运数最大的就是答案。
int a[100005];
int L[100005];
int R[100005];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
stack<int> lq,rq;
for(int i=1 ; i<=n ; i++)
{
while(lq.size() && lq.top()< a[i]) lq.pop();
if(lq.empty()) L[i] = 0;
else L[i] = lq.top();
lq.push(a[i]);
}
for(int i=n; i>=1 ; i--)
{
while(rq.size() && rq.top()< a[i]) rq.pop();
if(rq.empty()) R[i] = 0;
else R[i] = rq.top();
rq.push(a[i]);
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(L[i])
{
ans=max(L[i]^a[i],ans);
}
if(R[i])
{
ans=max(R[i]^a[i],ans);
}
}
cout<<ans<<endl;
}
题意:给一个不同数字的数字数组,一个k,要求删去一些数,使得数组中不能出现两个数x,y,使得x是y的k倍,求删去数的最小个数。
解:最开始想的太麻烦了,思路偏了,导致浪费了很多时间在这个水题上。实际上只需要将数组sort一下,对于每个数,lower_bound查找是否这个数乘k的数在数组里,在的话就删掉,就能保证删的最少。
ll a[100005];
bool mark[100005];
int main()
{
ll n,k,ans=0,x;
scanf("%lld %lld",&n,&k);
for(int i=0; i<n; i++)
{
scanf("%lld",&a[i]);
}
mset(mark,true);
sort(a,a+n);
for(int i=0; i<n; i++)
{
if(mark[i])
{
ans++;
x=lower_bound(a,a+n,a[i]*k)-a;
if(x<n&&a[x]==a[i]*k)
{
mark[x]=false;
}
}
}
printf("%lld\n",ans);
}
题意:给一棵树从点1~n,给出某些边坏掉了,选择一个k点,每次可以修好从1 ~ k以内的所有边,问最小选择几个,都哪些点,可以使树上所有边都是好的。
解:
学长讲题的时候思路太绕我没听懂。我好久没写过图论的题了,连存图都不会了,但是觉得明明可以从1直接遍历整个树,如果当前点最下面没有坏边或者下面没有点了,而这个点和他父亲节点之间是条坏边,那么就要这个点,其他情况全不要。这样得到的点集就是答案。我花了点时间复习了一下链式前向星存图,然后一边就过了。
struct edge
{
int to;
int next;
int t;
}E[maxn*2];
int head[maxn];
int ans[maxn];
int cnt=0,tot=0;
void add(int u,int v,int t)
{
E[cnt].to=v;
E[cnt].t=t;
E[cnt].next=head[u];
head[u]=cnt++;
}
int dfs(int u,int pre)
{
int flag,sf=0;
for(int i=head[u];i!=-1;i=E[i].next)
{
int v=E[i].to;
if(v==pre)continue;
flag=dfs(v,u);
if(flag==0&E[i].t==2)
ans[tot++]=v;
if(flag==1||E[i].t==2)
sf=1;
}
return sf;
}
int main()
{
memset(head,-1,sizeof(head));
memset(E,0,sizeof(E));
memset(ans,0,sizeof(ans));
int n;
cin>>n;
int u,v,t;
for(int i=1;i<=n-1;i++)
{
cin>>u>>v>>t;
add(u,v,t);
add(v,u,t);
}
dfs(1,0);
cout<<tot<<endl;
for(int i=0;i<tot;i++)
{
if(i!=tot-1)
cout<<ans[i]<<" ";
else cout<<ans[i]<<endl;
}
}
题意:
给一个大写字母串,只含26个大写字母的前K个,想让他相邻两个字母不能相同,每次可以把其中一个字母变成26个大写字母的前K个中的一个,问你最少多少次操作能够做到。
解:
浪费超多时间的水题,最后还没做出来,气的不行,听完讲题才知道自己脑回路卡死在了一起处理上,其实可以分情况的。其实很简单,就是分情况处理,当k=2时,只能是ABABA或者BABAB的情况,直接暴力;当k>2,当有相同的,s[i]==s[i+1],那就把是s[i+1]换成一个与s[i]和s[i+2]都不同的,一边遍历完事。
int n,k;
int solvel(string &s)
{
int ans1=0;
for(int i=0; i<n-1; i++)
{
if(s[i]==s[i+1])
{
int j=0,a,b,p;
a=s[i]-'A';
if(i+2<n)
{
b=s[i+2]-'A';
for(j=0; j<k; j++)
{
if(j!=a&&j!=b)
{
p=j;
break;
}
}
}
//cout<
if(j>=k||i+2>=n)
{
for(int z=0; z<k; z++)
{
if(z!=a)
{
p=z;
break;
}
}
}
ans1++;
s[i+1]='A'+p;
}
}
return ans1;
}
int main()
{
string s;
while(cin>>n>>k)
{
cin>>s;
int cnt=0,ans=0;;
if(k==2)
{
for(int i=0; i<n; i++)
{
if(i%2==0)
{
if(s[i]!='A')
cnt++;
}
else
{
if(s[i]!='B')
cnt++;
}
}
ans=cnt;
cnt=0;
for(int i=0; i<n; i++)
{
if(i%2!=0)
{
if(s[i]!='A')
cnt++;
}
else
{
if(s[i]!='B')
cnt++;
}
}
if(ans<=cnt)
{
cout<<ans<<endl;
for(int i=0; i<n; i++)
{
if(i%2==0)
{
cout<<'A';
}
else
{
cout<<'B';
}
}
cout<<endl;
}
else
{
cout<<cnt<<endl;
for(int i=0; i<n; i++)
{
if(i%2!=0)
{
cout<<'A';
}
else
{
cout<<'B';
}
}
cout<<endl;
}
}
else
{
cout<<solvel(s)<<endl;
cout<<s<<endl;
}
}
}