牛客练习赛14 B 区间的连续段 (倍增)
链接:https://ac.nowcoder.com/acm/contest/82/B
来源:牛客网
区间的连续段
时间限制:C/C++ 7秒,其他语言14秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给你一个长为n的序列a和一个常数k
有m次询问,每次查询一个区间[l,r]内所有数最少分成多少个连续段,使得每段的和都 <= k
如果这一次查询无解,输出"Chtholly"
输入描述:
第一行三个数n,m,k
第二行n个数表示这个序列a
之后m行,每行给出两个数l r表示一次询问
输出描述:
输出m行,每行一个整数,表示答案
备注:
对于100%的数据,1 <= n , m <= 1000000 , 1 <= ai , k <= 1000000000
题意:
给你一个数组,和一个整数k,和q次询问,每一次询问给你一个l,r
问你最少把数组分成多少个连续部分,使每一个连续的sum和小于等于k。
思路:
2进制倍思想,
因为n<=1e6 所以我们倍增数组只需要开到 20 ,因为 1<<20 是1048576 >1e6
我们开倍增数组 st[i][j] 表示 第i个 数右移1<<j 到的最远的距离,
那么我们维护好这个信息后,对于每一个询问,我们只需要贪心的求解即可。
lg[i] 代表 log2(i) 可以证明 从 l到r,我们可以在 log2(r-l+1) ,log2(r-l),log2(r-l-1)...log2(1) 选择一些数加上到达。
那么我们只需要贪心的 让当前的pos 右移 log2(r-l+1) 远是否小于等于R,如果小于等于就移动,然后再更细(小)一步的移动。即可,最后判断是否移动到了R来决定输出什么即可。
细节见代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== [ "<<x<<" ] =="<<endl; using namespace std; typedef long long ll; ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;} ll lcm(ll a, ll b) {return a / gcd(a, b) * b;} ll powmod(ll a, ll b, ll MOD) {ll ans = 1; while (b) {if (b % 2)ans = ans * a % MOD; a = a * a % MOD; b /= 2;} return ans;} inline void getInt(int* p); const int maxn = 1000010; const int inf = 0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ ll n, m, k; ll a[maxn]; ll lg[maxn]; int st[maxn][21]; int main() { //freopen("D:\\common_text\\code_stream\\in.txt","r",stdin); //freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); gbtb; cout << (1 << 20) << endl; cin >> n >> m >> k; repd(i, 1, n) { cin >> a[i]; } repd(i, 1, n) { lg[i] = lg[i / 2] + 1; } repd(i, 1, n) { a[i] += a[i - 1]; } int pos; repd(i, 0, 20) { st[n + 1][i] = n + 1; } for (int i = n; i >= 1; i--) { pos = upper_bound(a + 1, a + 1 + n, a[i - 1] + k) - a; st[i][0] = pos; repd(j, 1, 20) { st[i][j] = st[st[i][j - 1]][j - 1]; } } int l, r; repd(t, 1, m) { cin >> l >> r; pos = l; int ans = 0; for (int j = lg[r - l + 1]; j >= 0; j--) { if (st[pos][j] <= r) { pos = st[pos][j]; ans += (1 << j); } } if (st[pos][0] <= r) { cout << "Chtholly" << endl; } else { cout << ans + 1 << endl; } } return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ' ' || ch == '\n'); if (ch == '-') { *p = -(getchar() - '0'); while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 - ch + '0'; } } else { *p = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') { *p = *p * 10 + ch - '0'; } } }
本博客为本人原创,如需转载,请必须声明博客的源地址。
本人博客地址为:www.cnblogs.com/qieqiemin/
希望所写的文章对您有帮助。