zoukankan      html  css  js  c++  java
  • noip模拟【array】

    array

          by ysy

    【题目描述】

        给定一个长度为n的数列,每次你可以进行以下操作之一:

    (1)将一个数+a;

    (2)将一个数-a;

    (3)将一个数+b;

    (4)将一个数-b;

    你需要将所有数全部变为0,求最小操作数。

    【输入数据】

           第一行三个整数n,a,b,第二行n个整数x1~xn表示数列。

    【输出数据】

    一行一个整数表示答案。无解输出-1。

    【样例输入】

    2 2 3

    1 2

    【样例输出】

     3

    【数据范围】

    对于10%的数据,n,a,b,|xi|<=1000。

    对于30%的数据,n,a,b<=1000。

    对于另外10%的数据,a=1。

    对于另外10%的数据,a=2,b=3。

    对于100%的数据,1<=n<=105,1<=a,b<=109,|xi|<=109

    【题解思路】

    很容易转化成数学模型:ax+by = c,使(|x|+|y|)min。

    对于方程ax+by = c,我们可以用exgcd求出一组解。

    当a,b互质时,保证ax+by = c有解。

    设d = gcd(a,b).a/d*x+b/d*y = c/d;

    此时可求出一组特解:x',y'。

    则ax+by = c的通解可以表示为:x = c/d * x' + k * b/d,y = c/d * y' - k * a/d;

    然后如何使(|x|+|y|)min。考虑到对于上述通解,我们可以打表或意念理解,这是个单峰函数。

    即存在唯一且确定值k,使得|c/d*x' + k*b/d|+|c/d*y' - k* a/d|最小,尽可能使绝对值接近零,那么对于这两个数使得x取得最小的正数或最大的负数(绝对值尽量接近0)。

    时间复杂度 O(nlog|xi|)

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define ull unsigned long long
    #define rep(k,i,j) for(int k = i;k <= j; ++k) 
    #define FOR(k,i,j) for(int k = i;k >= j; --k)
    inline int read(){
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,a,b,k;
    inline void exgcd(int a,int b,int m,ll &x,ll &y){
        if(!b) x = m/a,y = 0;
        else {
            exgcd(b,a%b,m,x,y);
            swap(x,y);
            y -= a/b*x;
        }
    }
    inline int gcd(int a,int b){return b ? gcd(b,a%b) : a;}
    ll x,y,p;
    int main(){
        freopen("array.in","r",stdin);
        freopen("array.out","w",stdout);
        n = read(),a = read(),b = read();
        k = gcd(a,b);
        a /= k,b /= k;
        if(a<b) swap(a,b);
        rep(i,1,n){
            int j = read();
            if(j%k) printf("-1
    "),exit(0);
            exgcd(a,b,j/k,x,y);
            if(y<0) {
                x -= b*((-y)/a+1);
                y += a*((-y)/a+1);
            }
            x += b*(y/a);
            y -= a*(y/a);
            p += min(abs(x)+abs(y),abs(x+b)+abs(y-a));
        }
        printf("%lld
    ",p);
        return 0;
    } 
    /*
    2 2 3
    1 2
    */
    View Code
    G102的孤儿们都要好好的啊。
  • 相关阅读:
    MySQL常用函数介绍
    SQL语法基础之DROP语句
    MySQL常见报错汇总
    SQL语法基础之SELECT
    SQL语法基础之ALTER语句
    OpenStack技术栈-OpenStack的基础原理概述
    体验Hadoop3.0生态圈-CDH6.1时代的来临
    Windows下强制删除文件或文件夹(解除文件占用/Unlock)
    foreach Transform 同时chils.setParent引起的bug
    CharacterController平滑移动到某点
  • 原文地址:https://www.cnblogs.com/ve-2021/p/9862622.html
Copyright © 2011-2022 走看看