【NOIP2017提高A组冲刺11.4】Pacifist
2017-11-06 19:11
309 查看
Description:
在你面前有一个被加密了的数组,其原数组是一个等差序列,你面前的则是将原数组中的所有数字都对m 取模再打乱后而得到的新数组papyrus 给你出的谜题就是还原出原等差序列
保证数据有解,而且因为papyrus 喜欢质数,所以他给你出的谜题中的m 一定是质数
2 <= m <= 10^9 +7; 2 <= n <= 10^5,m 是质数,数组a 中所有数字两两不同
题解:
考场时瞎搞了个随机化,结果差点过了,事实证明这是对的,只是没有特判一种情况。目标在于求出公差,求出来了一切都好办。
考虑对于原等差数列,我选取一个数x,则会呈现这样的情况:
x - kb, …, x- b, x, x+b, …,x + kb, x + (k + 1)b,…
或者是:
…,x - (k + 1)b, x - kb, …, x - b, x, x +b,…,x+kb
发现x两边的数是关于它对称的。
于是可以推出一个结论,如果有a+b = 2x, 则a和b在原序列中的位置关于x对称,前提是n != mo。
于是可以随机一个x,如果a+b=2x,那么a,b这些数和x是原序列中连续的一段,剩余的也是原序列中连续的一段。
可以选取小的一段进行递归,直到剩两个数的时候就可以求出公差了。
一定要特判n = mo,不然会死循环。
时间复杂度可以认为是O(n log n)的。
出题人的做法是枚举首项,可以根据等差数列一次和公式推出公差,再代入二、三次和公式即可判断这个首项是否合法。
Code:
#include<cstdio> #include<cstdlib> #include<algorithm> #define ll long long #define fo(i, x, y) for(ll i = x; i <= y; i ++) using namespace std; const int N = 2e5 + 5; const ll ni_2 = 5e8 + 4; ll mo, n, a , b ; ll rand(int x, int y) { ll s = 0; fo(i, 1, 5) s = (s + rand()) % (y - x + 1); return s + x; } int d1 , d2 ; ll P(ll i, ll j) { if(j == i + 1) { int k = (a[j] - a[i] + mo) % mo; return k > mo / 2 ? mo - k : k; } ll m = rand(i, j), r = j; ll t1 = 0, t2 = 0; fo(k, i, j) { int ans = 0; ll x = (2 * a[m] - a[k] + mo) % mo; for(int l = i, r = j; l <= r; ) { int m = l + r >> 1; if(a[m] == x) { ans = m; break; } if(a[m] < x) l = m + 1; else r = m - 1; } if((ans && ans != k) || k == m) d1[++ t1] = a[k]; else d2[++ t2] = a[k]; } fo(k, i, i + t1 - 1) a[k] = d1[k - i + 1]; fo(k, i + t1, j) a[k] = d2[k - (i + t1) + 1]; if((t1 < t2 && t1 != 1) || t2 == 0 || t2 == 1) return P(i, i + t1 - 1); else return P(i + t1, j); } int main() { freopen("pacifist.in", "r", stdin); freopen("pacifist.out", "w", stdout); srand(51651131); scanf("%lld %lld", &mo, &n); fo(i, 1, n) scanf("%lld", &a[i]); if(n == mo) { printf("0 1\n"); return 0; } sort(a + 1, a + n + 1); ll g = P(1, n); sort(a + 1, a + n + 1); int r = 1; fo(i, 1, n) { int x = (a[i] - g + mo) % mo; int ans = 0; for(int l = 1, r = n; l <= r; ) { int m = l + r >> 1; if(a[m] == x) { ans = 1; break; } if(a[m] < x) l = m + 1; else r = m - 1; } if(!ans) { printf("%lld %lld\n", a[i], g); return 0; } } printf("%lld %lld\n", a[1], g); }
相关文章推荐
- Jzoj5449【NOIP2017提高A组冲刺11.4】Pacifist
- 【NOIP2017提高A组冲刺11.4】总结
- 【JZOJ 5449】【NOIP2017提高A组冲刺11.4】Pacifist
- Jzoj5450【NOIP2017提高A组冲刺11.4】Neutral
- 【NOIP2017提高A组冲刺11.4】Genocide
- Jzoj5451【NOIP2017提高A组冲刺11.4】Genocide(待补充)
- Jzoj5454【NOIP2017提高A组冲刺11.5】仔细的检查
- Jzoj5455【NOIP2017提高A组冲刺11.6】拆网线
- Jzoj5459【NOIP2017提高A组冲刺11.7】密室
- 【NOIP2017提高A组冲刺11.8】总结
- JZOJ5442【NOIP2017提高A组冲刺11.1】荒诞 三进制状压+欧拉序
- 【NOIP2017提高A组冲刺11.2】总结
- Jzoj5456【NOIP2017提高A组冲刺11.6】奇怪的队列
- Jzoj5443【NOIP2017提高A组冲刺11.2】字典序
- 【NOIP2017提高A组冲刺11.3】总结
- [JZOJ5451]【NOIP2017提高A组冲刺11.4】Genocide
- Jzoj5460【NOIP2017提高A组冲刺11.7】士兵训练
- jzoj5441【NOIP2017提高A组冲刺11.1】序列
- 【NOIP2017提高A组冲刺11.5】总结
- 【NOIP2017提高A组冲刺11.6】项链