题意:
给定 n 和 m ,就是对于一个 m*n 的矩阵,求从(1,1)到达(n,m)所需要的最小步数,题目限制是,对于上移,下移,左移,右移每个操作不能连续操作。
题解:
我们不难发现,当m和n的绝对值差在1以内的时候,最短步数都是 m+n-2
如图,当m=4时,若n=4,ans=6,若n=5,ans=7,但当n和m的绝对值超过1时,超过一个步数就+3,再超过一个就+1,以此类推,当然还要特判一下n和m等于1的情况
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e+7;
void solve()
{
int n,m;
cin>>n>>m;
if(n==1&&m==1){
cout<<0<<endl;
return ;
}if(n==1||m==1){
if(n+m>3){
cout<<-1<<endl;
return ;
}
}
int x=abs(n-m),y=min(n,m);
if(x<=1){
cout<<m+n-2<<endl;
return;
}
x--;
if(x%2==0)cout<<y+y-1+(x/2)*4<<endl;
else cout<<y+y-1+(x+1)/2*4-1<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)solve();
}
题意:
对于每组给的数据n和m,代表着一共有n个人和m个凳子,凳子可以绕成环状,然后输入n个数组
a【i】,1 <= i <= n,代表第i个人坐的位置左右分别需要a【i】个空位置,问所有人能不能满足自己的要求坐下来
题解:
若一组数据为
3 2 1 1 1 时
我们按照3个人的要求围成了一个圈坐下来,黄色的圈是空位置,一共用了6个座位
我们可以统计满足所有人需求时所用的座位数量,然后把所需座位数与拥有座位数进行对比;
我们可以从第一个人往最后有一个人的所需座位数遍历,第一个人需要ans=a【1】*2+1个座位数,第二个人需要ans+a【2】*2+1-a【1】,因为第二个人左边需要的位置数可以与第一个人右边的位置数重合,所以我们要减去a【1】,以此类推遍历到最后一个人,对于最后一任操作完以上操作之后,还要减去a【1】,因为座位实际上是围城一个环状的,最后一个人的右边的空座位就是第一个人左边的空座位,
当然,在从第一个人往最后一个人遍历的时候进行的操作的满族条件是第 i 个人所需的空位置数量大于第 i-1 个人的空位置数量,所以我们对a数组还要sort一下
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e+7;
ll a[N];
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;++i)cin>>a[i];
sort(a+1,a+1+n);
ll sum=0;
for(int i=1;i<=n;++i){
if(i==1)sum=a[i]*2+1;
else if(i!=n){
sum+=a[i]*2+1-a[i-1];
}
}
sum+=a[n]*2+1-a[n-1]-a[1];
if(sum>m)cout<<"NO"<<endl;
else cout<<"YES"<<endl;
}
int main()
{
int t;
cin>>t;
while(t--)solve();
}
题目:
对于给定的n个a【i】数组,还存在一个每个位上全是0的b【i】数组,每次可以将a【i】上的值对
b【i】进行 b【i】=b【i】-a【i】或b【i】=b【i】+a【i】操作,使得在k次操作之后,b数组可以满足:把连续的b数组分成两份,满足前一部分递减,后一部分递增
如输入
5
1 2 3 4 5
可以对b数组进行操作4次使得b为【-1,0,3,4,5】,此时满足题目条件
7
1 2 1 2 1 2 1
可以对b数组进行10次操作使得b为【-3,-2,-1,0,1,2,3】,其中每个位置的操作次数分别为【3,1,1,0,1,1,3】
题解:
我们发现最后b的值中,在不操作的位置的两边都是满足条件的,此时不操作的位置的结果就是0,其实我们可以对a数组进行操作,找到一个位置使得此位置对应的b数组上的位置结果为0,然后在a上这个位置的两边,分别递增,可以满足该位置的两侧的数组分别向数组的两个边界递增满足条件即可,
如对于一边的数据6 ,2 ,我们要使得这边朝右递增,变成6 ,8,我们需要对2操作6/2=3次,即2+2+2+2=8满足条件,这时候更新2位置的数值应为(6/2+1)*2=8,注意这里的除只是表示倍数,并不能使得3*2=6>6所以我们需要(3+1)*2=8才能使得结果变成6,8,我们需要对选定的位置两边分别进行类似的递增操作,即操作n-1次
这个题目n的最大值在5000以内,并且限制时间为2s,我们完全可以使用O(n^2)暴力进行,枚举每一个位置为0的下标
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=6000;
ll a[N],c[N],n;
void copy(){
for(int i=1;i<=n;++i)c[i]=a[i];
}
void solve()
{
cin>>n;
for(int i=1;i<=n;++i)cin>>a[i];
ll num=0x3f3f3f3f3f3f3f; 初始值为无穷大
for(int j=1;j<=n;++j){
copy();
int k=j;
ll ans=n-1;
if(c[k]<c[k-1])k=k-1;
for(int i=k-2;i>0;--i){
if(c[i+1]>=c[i]){
ans+=c[i+1]/c[i];
c[i]=(c[i+1]/c[i]+1)*c[i];
}
}
for(int i=k+2;i<=n;++i){
if(c[i]<=c[i-1]){
ans+=c[i-1]/c[i];
c[i]=(c[i-1]/c[i]+1)*c[i];
}
}
num=min(ans,num);
}
cout<<num<<endl;
}
int main()
{
solve();
}
注意答案num的初始值需要初始化为 long long 的无穷大,因为我开始只给 num 开了个long long的0x3f3f3f3f,初始值只有10的九次左右,所以我卡wa5了,今天出样例了才看见,样例给了5000个1,答案有10的十六次,所以爆了,所以要给num的初始值开大点,开9个3f后到了longlong的无穷大,有10的十九次,所以以后都开九个3f才是最保险的😭😭😭😭,以后只要内存够啥都用long long和0x3f3f3f3f3f3f3f3f3f,就不会卡在这些点上了呜呜,前两天的icpc也是,得记住摔跤的地方!!!