1. 程式人生 > >牛客國慶集訓派對Day3 A Knight

牛客國慶集訓派對Day3 A Knight

題意:略。

分析:規律題,打了表半天沒找出規律。。。

網友思路:

如果目的點不在第一象限,將其轉化到第一象限,且另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;
}