牛客国庆集训派对Day3 A Knight

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/tianwei0822/article/details/82940795

题目:点击打开链接

题意:略。

分析:规律题,打了表半天没找出规律。。。

网友思路:

如果目的点不在第一象限,将其转化到第一象限,且另m>n
若2*n>m>n
    若(n+m)是三的倍数,我可以通过走x个(1,2)和y个(2,1)到达,那么x+2x+2y+y=n+m,得x+y=(n+m)/3;
    若(n+m)%3==1,我可以走这样一步使得(-2,1),使得目的地和起点的曼哈顿距离还是3的倍数,因此答案是(n+m)/3+1
    若(n+m)%3==2,我可以走两步(-2,1),使得目的地和起点的曼哈顿距离还是3的倍数,因此答案是(n+m)/3+2
若m==2*n
   答案是n
若m>2*n
    第一种情况:
    我先尽量走(1,2),直到把n走完,走了n步,若把这时的点看做原点,目的地就是(m-2*n,0),
    转化成起点和目的点在同一直线上的问题
    第二种情况:
    我先走一步(-1,2),然后把(-1,2)当做起点,目的点变成(n+1,m-2)这时在求1+query(n+1,m-2)即可
    答案是两种情况中小的那个
    至于怎么求目的点和起点在同一坐标轴的问题,随便推理一下就知道了

题解:

不妨假设 x>=y>=0。
当 x<=2y 时,定义每一步的冗余值 wi=3-dx-dy,那么∑wi=∑(2-dx)=3*
步数-x-y,显然我们只需要最小化冗余值。我们先只用(+2,+1)(若 x 为奇数则
加一步(+1,+2))走到(x,y’),然后通过将(+2,+1)替换为 2 个(+1,+2)使得
0<=y-y’<3。
若 y-y’=0,则冗余值为 0,显然最小。
若 y-y’=1,则将(+1,+2)替换为(+2,+1)和(-1,+2)或将 2 个(+2,+1)替换为
(+1,+2),(+1,+2),(+2,-1),冗余值为 2,显然最小。(此处需要特判(2,2))
若 y-y’=2,则加上(+2,+1)和(-2,+1),冗余值为 4,由于不存在冗余值为 1
的步,所以最小

 x>2y 时,定义每一步的冗余值 wi=2-dx,那么∑wi=∑(2-dx)=2*步数-x,
显然我们只需要最小化冗余值。我们先只使用(+2,+1)走到(2y,y),然后用
(+2,+1)和(+2,-1)走到(x’,y)使得 0<=x-x’<4。
若 x-x’=0 则冗余值为 0,显然最小

若 x-x’=1 则将之前的(+2,+1)改为(+1,+2)和(+2,-1),冗余值为 1,显然最
小。(此处需要特判(1,0))
若 x-x’=2 则加上(+1,+2)和(+1,-2),冗余值为 2,由 x/2+y 的奇偶性可知
最小。
若 x-x’=3 则加上(+2,+1),(+2,+1),(-1,-2),冗余值为 3,由 x/2+y 的奇偶
性可知最小。
时间复杂度 O(t)

代码:

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(4)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<unordered_map>
#include<unordered_set>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<complex>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iomanip>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cctype>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define pt(a) cout<<a<<endl
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define rep(i,a,n) for (int i=a;i<=n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define PI acos(-1.0)
typedef pair<int,int> PII;
const ll mod = 1e9+7;
const int N = 1e6+10;

ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qp(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
int to[8][2]={{-2,-1},{-2,1},{-1,-2},{-1,2},{1,-2},{1,2},{2,-1},{2,1}};

ll t,n,m,ans;

ll gn(int x,int y) { ///max(n,m)<=2的情况特判
    if(x+y==0) return 0;
    else if(x+y==1) return 3;
    else if(x+y==2) return 2;
    else if(x+y==3) return 1;
    else return 4;
}

ll ln(ll x) {///在同一条线上的情况
    if(x==0) return 0;
    else if(x==1) return 3;
    else if(x%4==0) return x/2;
    else if(x%2==0) return x/2+1;
    else if((x/2)%2) return x/2+2;
    else return x/2+1;
}

ll sv(ll x,ll y) {
    ll s1,s2;
    s1=y+ln(x-2*y);
    x-=2,y+=1;///绕一步(规律)
    if(x<=2) s2=1+gn(x,y);
    else if(x>2*y) s2=1+y+ln(x-2*y);
    else if(x==2*y) s2=1+y;
    else if(x<2*y) s2=1+(x+y)/3+(x+y)%3;
    return min(s1,s2);///取最小
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    cin>>t;
    while(t--) {
        cin>>n>>m;
        n=abs(n),m=abs(m);
        if(n<m) swap(n,m);
        if(n<=2) ans=gn(n,m);
        else if(n==2*m) ans=m;
        else if(n>2*m) ans=sv(n,m);
        else ans=(n+m)/3+(n+m)%3;
        cout<<ans<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianwei0822/article/details/82940795