【补题】2020 CCPC 秦皇岛 I. Interstellar Hunter(exgcd,向量线性组合的等价转换)

题目链接:http://codeforces.com/gym/102769/problem/I
一开始想到贝祖定理,但是只能分别判断x和y方向上的,没办法组合起来判断。

思路分析

这道题考的其实主要不是贝祖定理,而是exgcd。
假设我现在我们有向量 ( a 1 , b 1 ) , ( a 2 , b 2 ) (a_1,b_1),(a_2,b_2) (a1,b1)(a2,b2)
考虑x方向上,若某横坐标c可以到达,则表示存在x,y,使得 a 1 x + a 2 y = c a_1x+a_2y=c a1x+a2y=c。由exgcd可知:该方程解的情况等价于 a 2 x + ( a 1 − a 2 ) y = c a_2x+({a1- a2})y=c a2x+(a1a2)y=c解的情况
并且,通过更损相减法我们可以知道,一直mod递归下去,a1和a2中最后会有一个变为0,因此,我们可以知道:两个数a,b线性组合是否有解等价于b,a-tb的线性组合是否有解。
通过上面的思考,我们将这个想法拓展到二维的向量a,b上:那也一定有 a x + b y = c ax+by=c ax+by=c解的情况等价于 b x + ( a − b ) y = c bx+(a-b)y=c bx+(ab)y=c的解的情况(将两维分开来看就可以懂了)。因此,我们可以利用这个式子,把a的x变成0,这样横坐标上只有b向量有贡献,就很好判断了。
这个思想甚至可以用在更高维度的向量问题上。
总结:k个n维向量的线性组合是否等价于某一n维向量,解的情况等价于n个n维向量线性组合是否等于该n维向量的解的情况。

#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
#define IOS ios_base::sync_with_stdio(0); cin.tie(0);
#define rep(i, a, n) for(int i = a; i <= n; ++ i)
#define per(i, a, n) for(int i = n; i >= a; -- i)
//#define ONLINE_JUDGE
using namespace std;
typedef long long ll;
const int mod=1e9+7;
template<typename T>void write(T x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
    {
        write(x/10);
    }
    putchar(x%10+'0');
}

template<typename T> void read(T &x)
{
    x = 0;char ch = getchar();ll f = 1;
    while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
    while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}

int gcd(int a,int b){return b==0?a:gcd(b,a%b);}
int lcm(int a,int b){return a/gcd(a,b)*b;};
ll ksm(ll a,ll n){
	ll ans=1;
	while(n){
		if(n&1) ans=(ans*a)%mod;
		a=a*a%mod;
		n>>=1;
	}
	return ans%mod;
}
//==============================================================
#define int ll
int t,q;
struct node{
    int x,y;
    node(int X=0,int Y=0){
        x=X;
        y=Y;
    }
};

void merge(node&a,node&b){
    if(!a.x&&!b.x){
        b.y=__gcd(b.y,a.y);
        a={0,0};
    }
    else if(!a.y&&!b.y){
        b.x=__gcd(a.x,b.x);
        a={0,0};
    }
    while(a.x!=0){
        int t=b.x/a.x;
        b.x-=t*a.x;
        b.y-=t*a.y;
        swap(a,b);
    }
    a.y=abs(a.y);
    if(b.x<0)b.x=-b.x,b.y=-b.y;
    if(a.y)b.y=(b.y%a.y+a.y)%a.y;
}

//b.x为0
bool check(node&a,node&b,int x,int y){
    //cerr<<a.x<<" "<<a.y<<" "<<b.x<<" "<<b.y<<" "<<x<<" "<<y<<endl;
    int t;
    if(a.x==0){
        if(x)return false;
        else t=0;
    }
    else t=x/a.x;
    //cerr<<t<<endl;
    x-=t*a.x;
    y-=t*a.y;
    if(x)return false;
    if(b.y==0)return y==0;
    else return y%b.y==0;
}

ll solve(){
    ll res=0;
    node a,b;
    for(int i=0;i<q;++i){
        //cerr<<i<<endl;
        //cerr<<i<<":"<<endl;;
        //cerr<<a.x<<" "<<a.y<<endl;
        //cerr<<b.x<<" "<<b.y<<endl;
        int opt;read(opt);
        if(opt==1){
            int x,y;
            read(x),read(y);
            if(a.x==0&&a.y==0)a.x=x,a.y=y;
            else if(b.x==0&&b.y==0){
                b.x=x;b.y=y;
                merge(b,a);
            }
            else{
                node t(x,y);
                merge(t,a);
                merge(t,b);
                merge(b,a);
            }
        }
        else{
            int x,y,w;
            read(x),read(y),read(w);
            if(check(a,b,x,y))res=res+1ll*w;
        }
    }
    return res;
}

signed main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
	//clock_t c1 = clock();
	//===========================================================
    read(t);
    int kase=0;
    while(t--){
        read(q);
        printf("Case #%lld: ",++kase);write(solve());putchar('\n');
    }
	//===========================================================
	//std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值