zoukankan      html  css  js  c++  java
  • 【ybtoj高效进阶 21286】等差数列(数学)(分类讨论)

    等差数列

    题目链接:ybtoj高效进阶 21286

    题目大意

    给你一个数组 A,里面元素互不相同,问你是否可以把它重排成一个数组 B,使得它在模 M 的意义下是等差序列。
    只需输出首项和公差即可。

    思路

    首先发现 (M) 是质数,那就说明无论公差是什么(反正他都是小于 (M)),那它在模 (M) 意义下的循环节一定是 (M),也就是依次把 (0sim M-1) 的数都遍历一遍。

    考虑进行分类讨论,首先随便找到两个数的差,那它肯定是可以用 (Kd) 表示的。((d) 是公差,(K) 就是一个普通的整数)

    如果 (2nleqslant M),那就应该恰好有 (K) 个数字 (x) 是满足 (x+Kd) 是不在这个序列中的。那我们就可以得到 (K) 从而得到 (d)
    说明:那我们 (+Kd) 就相当于跳到它等差序列后面 (K) 位,那如果它是一个等差序列,那 (n-K+1sim n) 项加上之后就是空的,一共是 (K) 个。
    但因为它是一个环状,所以有限制条件是 (2nleqslant M),这样它就算是最后一个加了也不会转一圈那么多。

    那接着就是 (2n>M),这个时候最后一个加了就会超过一圈了。
    那似乎又变得很难搞了?
    其实不,你想想不是数组中的那一半。
    对,它也是等差序列啊,你可以求那个等差序列的答案,然后移一下首项就好啦!

    接着考虑如何实现,用 STL 的 lower_bound 即可实现。

    代码

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    
    using namespace std;
    
    ll T, m, n, a[100001];
    ll fir, b[100001], t, d;
    bool in[100001];
    
    ll ksm(ll x, ll y) {
    	ll re = 1;
    	while (y) {
    		if (y & 1) re = re * x % m;
    		x = x * x % m;
    		y >>= 1;
    	}
    	return re;
    }
    
    void work(ll *a, ll n) {
    	if (n == 1) {
    		fir = a[1]; d = 1;
    		return ;
    	}
    	
    	ll kd = a[2] - a[1], k = 0;
    	for (int i = 1; i <= n; i++) {
    		if (a[lower_bound(a + 1, a + n + 1, (a[i] + kd) % m) - a] != (a[i] + kd) % m)
    			k++;
    	}
    	
    	d = kd * ksm(k, m - 2) % m; fir = -1;
    	for (int i = 1; i <= n; i++) {
    		if (a[lower_bound(a + 1, a + n + 1, (a[i] - d + m) % m) - a] != (a[i] - d + m) % m) {
    			if (fir == -1) fir = a[i];
    				else {
    					fir = -1;
    					return ;
    				}
    		}
    	}
    }
    
    int main() {
    //	freopen("sequence.in", "r", stdin);
    //	freopen("sequence.out", "w", stdout);
    	
    	scanf("%d", &T);
    	while (T--) {
    		memset(in, 0, sizeof(in));
    		
    		scanf("%lld %lld", &m, &n);
    		for (int i = 1; i <= n; i++) {
    			scanf("%lld", &a[i]);
    		}
    		
    		sort(a + 1, a + n + 1);
    		
    		ll kd = a[2] - a[1], k = 0;
    		if (n * 2 <= m) {
    			work(a, n);
    		}
    		else {
    			t = 0;
    			for (int i = 0; i < m; i++)
    				if (a[lower_bound(a + 1, a + n + 1, i) - a] != i)
    					b[++t] = i;
    			work(b, t);
    			if(fir != -1) {
    				fir = (fir + d * t % m) % m;
    			}
    		}
    		
    		if (fir == -1) {
    			printf("-1
    ");
    			continue;
    		}
    		printf("%lld %lld
    ", fir, d);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    决策树
    结巴分词demo
    线性回归分析波士顿房价
    将python的字典格式数据写入excei表中
    ubuntu16.04电脑重启/关机卡死问题记录
    Hadoop 平台搭建
    Linux 常用命令
    灰度共生矩阵
    图像类型
    linux中的一些常用命令
  • 原文地址:https://www.cnblogs.com/Sakura-TJH/p/YBTOJ_GXJJ_21286.html
Copyright © 2011-2022 走看看