中文题意
给出两个整数,现在要你寻找某个序列,保证数组中相邻两个数差值的绝对值不大于,并且,最终使得。要你求解合法的序列最小的长度是多少。
Solution
我们拿到题目,看到数据范围就只能考虑直接计算或者二分解答两种方法。优先考虑能不能把题目转化为二分再去判断是否成立。
对于给定长度,并且的序列,很显然我们可以找到他可以构建的上下界,它可以构造的下界就是全部填充,得到和为,那么它的上界如何考虑,当的时候,我们只能实现一个递减的等差数列构建,上界就是,这个是等差数列求和公式。当的时候我们怎么办呢,画图发现,我们要使得,那么它的结尾一定有项是递减的等差数列,那么第一项一定是,第项也一定是,那么我们要保证这个前提就很容易发现我们前半段是一个具备对称性的分配,直接对前半部分分奇偶计算即可。
那么接下来考虑我们能不能去二分这个,如果不满足的话,那么我们一定要提高它的上界那就只能把变大,如果满足的话,我们尝试减小它的上界,看看能不能再次满足,总之就是寻找第一次上界大于等于的。但是还要注意数量级是,如果直接从到二分,那么计算他们的等差数列会爆,两种解决办法,上,第二种是寻找新的二分上界,很明显发现如果完全对称的话,就是我们可能找到的最大的,列出式子进行化简,可以发现差不多在左右,这样就可以压缩在了。
如果要交要用这个编译器,但是牛客没有。。
#include <bits/stdc++.h> using namespace std; #define js ios::sync_with_stdio(false);cin.tie(0); cout.tie(0) #define all(__vv__) (__vv__).begin(), (__vv__).end() #define endl "\n" #define pai pair<int, int> #define ms(__x__,__val__) memset(__x__, __val__, sizeof(__x__)) #define rep(i, sta, en) for(int i=sta; i<=en; ++i) #define repp(i, sta, en) for(int i=sta; i>=en; --i) typedef long long ll; typedef unsigned long long ull; typedef long double ld; inline ll read() { ll s = 0, w = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar()) if (ch == '-') w = -1; for (; isdigit(ch); ch = getchar()) s = (s << 1) + (s << 3) + (ch ^ 48); return s * w; } inline void print(ll x, int op = 10) { if (!x) { putchar('0'); if (op) putchar(op); return; } char F[40]; ll tmp = x > 0 ? x : -x; if (x < 0)putchar('-'); int cnt = 0; while (tmp > 0) { F[cnt++] = tmp % 10 + '0'; tmp /= 10; } while (cnt > 0)putchar(F[--cnt]); if (op) putchar(op); } inline ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; } ll qpow(ll a, ll b) { ll ans = 1; while (b) { if (b & 1) ans *= a; b >>= 1; a *= a; } return ans; } ll qpow(ll a, ll b, ll mod) { ll ans = 1; while (b) { if (b & 1)(ans *= a) %= mod; b >>= 1; (a *= a) %= mod; }return ans % mod; } const int dir[][2] = { {0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1} }; const int MOD = 1e9 + 7; const int INF = 0x3f3f3f3f; struct Node { ll val; int id; bool operator < (const Node& opt) const { return val < opt.val; } }; const int N = 1e6 + 7; ll n, H; ll p[N]; /* (1+k/2)*(k/2)*2 + (k+1)/2 = n */ ll calc(ll a, ll b) { return (a + b) * (b - a + 1) / 2; } bool check(int x) { ll res = 0; if (x <= H) res = calc(1, x); else { res = calc(1, H - 1); x -= H - 1; if (x & 1) res += calc(H, H + x / 2) + calc(H, H + x / 2 - 1); else res += 2 * calc(H, H + x / 2 - 1); } return res >= n; } void solve() { n = read(), H = read(); int l = 1, r = 2 * sqrt(n) + 100, ans; while (l <= r) { int mid = l + (r - l >> 1); if (check(mid)) ans = mid, r = mid - 1; else l = mid + 1; } print(ans); } int main() { //int T = read(); while (T--) solve(); return 0; }