zoukankan      html  css  js  c++  java
  • Codeforces Round #698 (Div. 2)

    ( ext{C - Nezzar and Symmetric Array})

    题目

    简要题意

    有一个长度为 (2n) 的数列 (a),其中每个数字都 互不相同,并且它还满足这样的条件:

    • 对于任意 (1le ile 2n) 都存在一个 (j)(1le jle 2n),有 (a_i=-a_j)

    但你不知道这个数列,你只知道一个长度为 (2n) 的数列 (d),有 (d_i=sum_{j=1}^{2n}|a_i-a_j|)

    数据范围与提示

    有多组数据 (le 10^5)(1le nle 10^5, 0le d_ile 10^{12}),且 (sum nle 10^5)

    解法

    #1. 一种方法

    看到了 “某点与其它点的距离之和”,我们不禁将数轴画了出来。

    显然相对原点对称的两点是等价的,而且要求数字 互不相同。那就首先无脑排个序,判断一下所有 (d) 值是否只出现两次,不是就是 no 了。

    假设我们将 (a) 数列中 (>0) 的项拉出来再排个序,得到新的 (a) 数列,再把 (d) 数列中重复的项删掉。

    初中老师告诉我们,(a_i) 对应着 (d_i),而且 (d_1) 值就是 (2 imessum_{i=1}^{n}a_i)

    对于 (d_{i},(i>1)),我们思考它与 (d_{i-1}) 之差代表了什么。显然对于 (1le j<i),在计算距离时 (d_i)(d_{i-1}) 都多算了 (2(a_i-a_{i-1}))。故 (d_i-d_{i-1}=2(i-1)(a_i-a_{i-1}))

    这样我们可以计算出相邻 (a) 的差值,最后拿去与 (d_1) 检验即可。

    需要注意的是,我们不能用差值确定 (a_1),但可以算出 (-na_1+sum_{i=1}^n a_i),所以最后只用判断能否整除 (n)

    还有几个特判,放在代码里了。

    #2. 另一种方法

    (mathtt{By}) 胖头鱼学员

    还是假设我们将 (a) 数列中 (>0) 的项拉出来再排个序,得到新的 (a) 数列,再把 (d) 数列中重复的项删掉。

    由于对称性,你会发现 (d_n=n imes 2a_n)

    对于 (d_{n-1}),对于在 ([-a_{n-1},a_{n-1}]) 中的点可以和 (d_n) 一样计算,但我们还少算了 (a_n,-a_n)(a_{n-1}) 的距离即 (2a_n)

    所以

    [d_{n-1}=(n-1) imes 2a_{n-1}+2a_n ]

    总结一下,有

    [a_i=frac{d_i-sum _{j=i+1}^n a_j}{2i} ]

    这样可以逆序构造出 (a_i),并顺便判断是否合法。

    代码

    #1. 一种方法

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
    #define print(x,y) write(x),putchar(y) 
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    
    typedef long long ll;
    
    const int maxn=2e5+5;
    
    ll d[maxn];
    int n;
    
    bool Single_Same() {
    	for(int i=1;i<n;i+=2)
    		if(d[i]^d[i+1])
    			return true;
    	for(int i=3;i<n;i+=2)
    		if(d[i]==d[i-1])
    			return true;
    	return false;
    }
    
    int main() {
    	rep(T,1,read(9)) {
    		n=read(9)*2;
    		rep(i,1,n) d[i]=read(9ll);
    		sort(d+1,d+n+1);
    		if(Single_Same()) {
    			puts("NO"); continue;
    		}
    		ll sum=0; bool flag=true;
    		for(int i=3;i<n;i+=2) {
    			if((d[i]-d[i-1])%(i-1)==0)
    				sum+=(d[i]-d[i-1])/(i-1)*(n-i+1)/2;
    			else {
    				puts("NO"); flag=false; break;
    			}
    		}
    		if(!flag) continue;
    		if(d[1]&1) {
    			puts("NO"); continue;
    		}
    		d[1]>>=1; 
    		// 这里需要保证严格大于,排除 a_1=0 的情况
    		if(d[1]>sum and (d[1]-sum)%(n/2)==0)
    			puts("YES");
    		else puts("NO");
    	}
    	return 0;
    }
    

    #2. 另一种方法

    # include <algorithm>
    # include <iostream>
    
    using namespace std;
    
    const int kMaxN = 2e5 + 1;
    long long T, n, d[kMaxN];
    
    bool Check() {
      for (int i = 1; i <= n * 2; i += 2) {
        if (d[i] != d[i + 1]) {
          return 1;
        }
      }
      return 0;
    }
    
    string Solve() {
      scanf("%lld", &n);
      for (int i = 1; i <= n * 2; i++) {
        scanf("%lld", &d[i]);
      }
      sort(d + 1, d + 2 * n + 1);
      if (Check() == 1) {
        return "NO
    ";
      }
      long long id = 2 * n, flag = 1, num = 2 * n, sum = 0, last = 0;
      while (id) {
        if ((d[id] - 2 * sum) % num != 0 || (d[id] - 2 * sum) / num <= 0) {
          return "NO
    ";
        } else {
          if (last != 0 && last <= ((d[id] - 2 * sum) / num)) {
            return "NO
    ";
          }
          last = ((d[id] - 2 * sum) / num);
          sum += ((d[id] - 2 * sum) / num), id -= 2, num -= 2;
        }
      }
      return "YES
    ";
    }
    
    int main() {
      scanf("%lld", &T);
      while (T--) {
        cout << Solve();
      }
      return 0;
    }
    

    ( ext{D - Nezzar and Board})

    ( ext{BiBi Time!})

    感觉自己数学好辣鸡啊。

    解法

    结论:(x_1=0) 时,有 (k)(g=gcd_{i=2}^n x_i) 整除则可行,否则不可行。

    实际上这是个充要条件,我们只需证明以下两个结论即可:

    • 可行 (Rightarrow) (k)(gcd_{i=2}^n x_i) 整除。

      显然当前黑板上每个数都是 (g) 的倍数,那么 (2x-y) 也是 (k) 的倍数。

    • (k)(gcd_{i=2}^n x_i) 整除 (Rightarrow) 可行。

      先考虑只用 (x,y) 两个数。这里有个奇妙的发现 —— (x) 实际上是 (2x-y)(y) 的中点!

      于是对于 (x_1=0,x_2),我们可以构造出所有 (x_2) 的倍数。所以这个结论在 (n=2) 时成立。

      考虑使用归纳法,已知在 (n-1) 情况下结论成立。

      (g_0=gcd_{i=2}^{n-1} x_i,g_1=gcd_{i=2}^{n} x_i)

      根据裴蜀定理(它适用于 整数),方程 (g_0s-x_nt=g_1) 必有整数解 (s=s_0+dfrac{kx_n}{g_1},t=t_0+dfrac{kg_0}{g_1} (kin Bbb Z))

      其中 (g_0s)(g_0) 倍数可以构造得出,(x_nt)(x_n) 的倍数,这可以用 (x_1=0,x_n) 来构造。

      事实上,只要 (g_0s,x_nt) 中有一个为偶数,我们就可以将 (g) 用类似 “(2x-y)” 的方式来表示。

      显然若 (dfrac{kx_n}{g_1},dfrac{kg_0}{g_1}) 中有一个数为奇数则满足这个条件。考虑 (g_1) 必和 (x_n,g_0) 中一个数拥有相等的 (2) 的幂次。

    如果 (x_1 eq 0) 呢?我们将每个数都减去 (x_1),这相当于在数轴上的平移,所以是等价的。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i,_l,_r) for(signed i=(_l),_end=(_r);i<=_end;++i)
    #define print(x,y) write(x),putchar(y) 
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
    
    typedef long long ll;
    
    const int maxn=2e5+5;
    
    int n;
    ll k,a[maxn];
    
    int main() {
    	rep(T,1,read(9)) {
    		n=read(9),k=read(9ll);
    		rep(i,1,n) a[i]=read(9ll);
    		ll g=a[2]-a[1];
    		/*
    			gcd(x_2-x_1,x_3-x_1,...,x_n-x_1)=gcd(x_2-x_1,x_3-x_2,...,x_n-x_{n-1})
    			可以用 gcd(a,b)=gcd(a-b,b) 证明
    		*/
    		rep(i,3,n)
    			g=gcd(g,a[i]-a[i-1]);
    		puts((k-a[1])%g?"NO":"YES");
    	}
    	return 0;
    }
    

    ( ext{E - Nezzar and Binary String})

    解法

    考虑反着做,因为有一个 “短浅” 的目标态。而由于每次改变量 严格小于 区间长度一半,我们只有一种选择方法。模拟即可。

  • 相关阅读:
    数据库30条规范
    数据库索引原理
    HashMap的实现原理
    Google 和 Baidu 常用的搜索技巧
    Arrays工具类十大常用方法
    fastjson将json格式null转化空串
    SolrCloud的介绍
    网页背景图片自适应浏览器大小
    addlinkedserver
    常用
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/14928815.html
Copyright © 2011-2022 走看看