小红的项链

思路:我们可以先求出来两两之间的距离,然后对距离进行排序,如下图所示:

容易发现,交换一定是发生在不同颜色的珠子之间(相同颜色珠子交换没意义)
对于输出-1的情况很好判断,就是不考虑交换次数,直接让他们尽可能离得远,如果k*3<n则输出-1,这里也有一个坑,就是说k是小于1e9的,但是3k就是可能溢出int了,因此需要开long long,这里提醒一下大家还是尽量把变量都设置成int类型吧
我们可以先计算出三者之间两两距离并对其进行排序,我们参照上图观察下相邻交换的本质是什么,假如C向A移动一个(也就是和左边的交换),那么d3--,d2++,也就是说交换本质就是使得一个--另一个++而且任意两个均可,因此我们只需要把三个都变为k及以上即可,那么我们每次都选择让最小的--,最大的++,也就是只让最初两个最小的距离都变为k即可,因此就很简单了,下面是代码:
#include<bits/stdc++.h>
using namespace std;
long long a[6],d[6];
int main()
{
int T;
cin>>T;
while(T--)
{
long long n,k;
scanf("%lld%lld%lld%lld%lld",&n,&k,&a[1],&a[2],&a[3]);
if(n<3*k) printf("-1\n");
else//肯定可以安置,且最大次数为2
{
sort(a+1,a+4);
d[1]=a[2]-a[1],d[2]=a[3]-a[2],d[3]=a[1]+n-a[3];//计算三者距离
sort(d+1,d+4);
long long t=0;
printf("%lld\n",max(t,k-d[1])+max(t,k-d[2]));
}
}
return 0;
}
插一句题外话,我一开始读这道题的时候读错了,误以为可以任意交换两个位置,写的比较复杂,但我觉得如果这样修改倒也是一道很不错的题目,因此也给出这道题目的解法,由于没有提交,因此不确定是否正确,还请大家多验证。
思路:容易发现,交换一定是发生在不同颜色的珠子之间(相同颜色珠子交换没意义)
而且由于是环,也就是每个位置并无本质区别,因此答案最多是2
对于输出-1的情况很好判断,就是不考虑交换次数,直接让他们尽可能离得远,如果k*3<n则输出-1,我们依旧是先计算出三者之间两两距离,并将其排序为d1<d2<d3,我们需要对其进行分情况讨论,假如d1>=k,那么直接是满足的直接输出0即可,对于d1<k的情况:
我们对d2进行讨论,假如d2<k:
依旧可以参照上面那张图,由于答案不可能大于2,因此我们只需要考虑移动一次是否可行,由于我们同时要改变d1和d2,那么我们只能移动B点至另一侧,这个时候A和C之间的距离变为了d1+d2,而B点则放在AC原来距离的中间,也就是B',那么只有d1+d2>=k且d3>=2*k才满足,否则直接输出2即可

对于d2>=k,由于d3>=d2,因此我们很容易想到是将A向C的方向移动,那么这个时候只需要判断d1+d3是否大于2*k即可,讨论完毕。整体来说这样一修改还是比原来复杂不少的,不过也可以锻炼下思维
代码:
#include<bits/stdc++.h>
using namespace std;
int a[6],d[6];
int main()
{
int T;
cin>>T;
while(T--)
{
int n,k;
scanf("%d%d%d%d%d",&n,&k,&a[1],&a[2],&a[3]);
if(n<3*k) printf("-1\n");
else//肯定可以安置,且最大次数为2
{
sort(a+1,a+4);
d[1]=a[2]-a[1],d[2]=a[3]-a[2],d[3]=a[1]+n-a[3];//计算三者距离
sort(d+1,d+4);
if(d[1]>=k) printf("0\n");
else
{
if(d[2]<k)//d[1]<d[2]<k的情况,此时d[3]>k
{
if(d[1]+d[2]>=k&&d[3]>=2*k) printf("1\n");
else printf("2\n");
}
else
{
if(d[3]+d[1]>=2*k) printf("1\n");
else printf("2\n");
}
}
}
}
return 0;
}
小红玩纸牌

思路:思路比较直接,先对牌进行排序(花色相同排一块,再按照大小来排),直接枚举求解即可
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
struct node{
int value,cnt;
char color[2];
}p[N];
bool cmp(node a,node b)
{
//先按照花色排序,再按照大小排序
if(a.color[0]!=b.color[0]) return a.color[0]<b.color[0];
return a.value<b.value;
}
int main()
{
int n;
long long ans=0;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d%d%s",&p[i].value,&p[i].cnt,p[i].color);
sort(p+1,p+n+1,cmp);
for(int i=1;i+4<=n;i++)
{
bool flag=true;//记录从i开始的连续五种排是否满足同花顺
int mn_cnt=p[i].cnt;//记录最小张数
for(int j=i+1;j<=i+4;j++)
{
if(p[j].color[0]!=p[j-1].color[0]||p[j].value!=p[j-1].value+1)
{
flag=false;
break;
}
mn_cnt=min(mn_cnt,p[j].cnt);
}
if(!flag) continue;
ans+=mn_cnt;
for(int j=i+1;j<=i+4;j++)
p[j].cnt-=mn_cnt;
}
printf("%lld",ans);
return 0;
}
小红的好数组

思路:有一个有意思的问题就是说,一个坐标轴上给定n个数,现在求一个点使得n个点到改点的位置和最小,这道题答案就是给这n个坐标排序,中位数即是答案(n为偶数的话则中间两个点之间任意一个位置均可),证明也很简单,你只需要设这个点坐标为x,那么你把其余所有点到这个点距离表示出来,然后相加,根据单调性很容易证明
那么这道题类似,唯一不同的是可以允许一个点不用到达,那么容易发现,假设我们最终这n-1个数都变为x,那么离x最远的一定是一开始的n个数中最小或者最大的之一,因此我们枚举这两种情况求一个最小值即可
需要注意,如果这n个数都相同,也是需要操作一次变成好数组的
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int a[N],b[N];
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
sort(a+1,a+n+1);
if(a[1]==a[n])
{
printf("1");
return 0;
}
long long ans=2e18+100,sum=0;
//第一种情况,最小的数不需要变为相同的元素
for(int i=1;i<n;i++)
b[i]=a[i+1];
int len=n-1;
int mid=(len+1)/2;//中间位置
for(int i=1;i<=len;i++)
sum+=abs(b[i]-b[mid]);
ans=min(ans,sum);
//第二种情况,最大的数不需要变为相同的元素
for(int i=1;i<n;i++)
b[i]=a[i];
sum=0;
for(int i=1;i<=len;i++)
sum+=abs(b[i]-b[mid]);
ans=min(ans,sum);
printf("%lld",ans);
return 0;
}
小红的子串权值和

思路:这种题目显然无法直接暴力求解,第一眼就是求解每个位置的贡献,比如一个子串是01110,中间这个111的整个贡献是1.那么这个贡献应该归结给谁,我们可以统一归结给最左边的1,那么我们就要考虑最左边的这个1的贡献了,容易发现,只要区间左端点在这个位置及其左边,而区间右端点在这个位置及其右边,这个1的贡献总能被算到,因此这个1的贡献就是其左边数字个数(包含自身)*右边数字个数(包含自身),对于处于这样位置的0也是同理。我们考虑下第二个1的贡献,如果区间左端点在其左边(不包含自身),那么也就是说它左边的1也会被包含,那么这个连续1的区间贡献就不会被算作它头上,因此区间左端点只能是它自己这个位置,而右端点则无需考虑,那么贡献就是1*右边数字个数(包含自身),写到这就非常清楚了,直接根据左边是否和自己相同分情况讨论一下,算一下贡献即可。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int main()
{
int n;
cin>>n;
string s;
cin>>s;
long long ans=0;
for(int i=0;i<n;i++)
{
long long l=1;
if(i!=0&&s[i]!=s[i-1])
l=i+1;
ans+=l*(n-i);
}
printf("%lld",ans);
return 0;
}