题目描述
Henry profiles a high load database migration script. The script is the list of n transactions. The i-th transaction consists of ai queries. Henry wants to split the script to the minimum possible number of batches, where each batch contains either one transaction or a sequence of consecutive transactions, and the total number of queries in each batch does not exceed t.
Unfortunately, Henry does not know the exact value of t for the production database, so he is going to estimate the minimum number of batches for q possible values of t: t1, t2, … , tq. Help Henry to calculate the number of transactions for each of them.
输入
The first line contains a single integer n — the number of transactions in the migration script (1 ≤ n ≤ 200 000).
The second line consists of n integers a1, a2,… , an — the number of queries in each transaction (1 ≤ ai; ∑ai ≤ 106).
The third line contains an integer q — the number of queries (1 ≤ q ≤ 100 000).
The fourth line contains q integers t1, t2,… , tq (1 ≤ ti ≤∑ai).
输出
Output q lines. The i-th line should contain the minimum possible number of batches, having at most ti queries each. If it is not possible to split the script into the batches for some ti, output “Impossible”
instead.
Remember that you may not rearrange transactions, only group consecutive transactions in a batch.
样例输入 Copy
6
4 2 3 1 3 4
8
10 2 5 4 6 7 8 8
样例输出 Copy
2
Impossible
4
5
4
3
3
3
思路:
原本自己写出来的,队友又去搜的题解。思路用的是二分,队友害羞不想露铭,哎呀,不小心暴露了。
思维
不知道是啥算法,通常不知道啥算法我就说是思维
首先理解题意:
我们可以这样了理解给出你
N
N
N个石头,每个石头重
a
a
a i ,然后给出你
M
M
M个篮子,每个篮子可以最大承重量为
b
b
bi . 问你如果用每个篮子装下这
N
N
N个用几个篮子(顺序不能变),不可以装就直接输出“Impossible”。
可以这样理解,看每个人的理解了,简化下题意。
思路:
- 首先我们找出不可以装的,如果有石头比篮子大,就是一个篮子只装这一个都装不下,更别说装这个石头后再装其他的了。所以记录下 N N N个石头重量最大的,比较篮子最大承重与其大小,篮子最大承重小于石头重量最大就直接输出“Impossible”。
- 然后我们看能装下的,
看下这个图,就是构造一下这个前缀和数组,标记每个后端点,也就是整个石头的。
我们可以拿 5 5 5大的篮子
第一个篮子只能装下4,他后面的五是空的,(这里你可以这样想就是把所有石头都分成最小块的石头,你可以这样看,但是取石头的你必须整个整个的取,因为石头实际不能拆)这样第一次取就是取到第一个指针 4 4 4这个位置,然后在拿过来个篮子,装到 ( 4 + 5 ) (4+5) (4+5)也就是 9 9 9整好吧 2 2 2和 3 3 3这两块石头装进去,这样再去换篮子,装到 ( 9 + 5 ) (9+5) (9+5)也就是 14 14 14但是 14 14 14是下一个石头的一部分,你还不能拆分石头所以只能被迫装前面的(也就是 13 13 13),然后重新申请个篮子装后面的石头,这样下个篮子装到 13 + 5 13+5 13+5 也就是 18 18 18这是我么你发现他已经把所有石头都装进去了,这时就是所用的所有篮子。最后构造成的新数组就是这样的(用于指针偏移)我也不知道叫啥
这样上面的应该也就是说的差不多了。
- 但是这样只能过90 因为他还会T掉,他要是100000个2 直接就是超时,所以为了不让他超时,也为了让我们不用做多余的计算,我们用上 备 忘 录 备忘录 备忘录这样我们就不用担心他会多算了,只要是算过直接出答案就行了。
- 下面的两个代码也挺好的,
代码:
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include <immintrin.h>
#pragma GCC optimize(2)
#include <map>
#include <queue>
#include <string>
#include<iostream>
#include<stdio.h>
#include<string.h>
#include <algorithm>
#include <math.h>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
typedef pair<ll,ll> pii;
#define mem(a,x) memset(a,x,sizeof(a))
#define debug(x) cout << #x << ": " << x << endl;
#define rep(i,n) for(int i=0;i<(n);++i)
#define repi(i,a,b) for(int i=int(a);i<=(b);++i)
#define repr(i,b,a) for(int i=int(b);i>=(a);--i)
const int maxn=1e6+100;
const int maxm=2e5+100;
#define inf 0x3f3f3f3f
#define sf scanf
#define pf printf
const int mod=998244353;
const int MOD=10007;
inline int read() {
int x=0;
bool t=false;
char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
int n,m,maxx;
int a[maxm],ans[maxn],b[maxn],sum,res;
#define read read()
int main(){
n=read;
sum=0;
for(int i=1;i<=n;i++){
a[i]=read;
sum+=a[i];
ans[sum]=1;
maxx=max(a[i],maxx);
}
for(int i=1;i<=sum+1;i++) {
if(ans[i]){
ans[i]=i;
}else {
ans[i]=ans[i-1];
}
}
sf("%d",&m);
int l;
for(int i=1;i<=m;i++){
l=read;
if(l<maxx) puts("Impossible");
else {
if(b[l]) pf("%d\n",b[l]);
else{
res=0;
for(int j=0;j+l<sum;j=ans[j+l]){
res++;
}
pf("%d\n",res+1);
b[l]=res+1;
}
}
}
return 0;
}
/**************************************************************
Problem: 17079
User: 2020Team11
Language: C++
Result: 正确
Time:51 ms
Memory:10616 kb
****************************************************************/
单纯整体二分:
#include<cstring>
#include<cstdio>
#include<map>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
typedef long long ll;
inline int Read()
{
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-') f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
return x*f;
}
const int N=2e5+5;
struct node{int k,id;}qry[N<<1],ql[N<<1],qr[N<<1];
int n,m;
int val[N],ans[N],sum,maxx,cum[N];
int check(int mid)
{
int l=0,cnt=0;
while(l<n)
{
l=upper_bound(cum+l,cum+1+n,cum[l]+mid)-cum-1;
cnt++;
}
return cnt;
}
int bir(int K)
{
int l=maxx,r=sum;
int ret=sum,mid;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)<=K)
{
ret=mid;
r=mid-1;
}
else l=mid+1;
}
return ret;
}
void divide(int l,int r,int s,int t)
{
if(s>t) return;
if(l==r)
{
for(int i=s;i<=t;i++)
{
if(qry[i].k<maxx)ans[qry[i].id]=-1;
else ans[qry[i].id]=l;
}
return;
}
int mid=(l+r)>>1,lp=0,rp=0;
int maxMin=bir(mid);
for(int i=s;i<=t;i++)
{
if(qry[i].k>=maxMin)ql[++lp]=qry[i];
else qr[++rp]=qry[i];
}
for(int i=s;i<=s+lp-1;i++) qry[i]=ql[i+1-s];
for(int i=s+lp;i<=t;i++) qry[i]=qr[i+1-s-lp];
divide(l,mid,s,s+lp-1),divide(mid+1,r,s+lp,t);
}
int main()
{
n=Read();
maxx=sum=0;
for(int i=1;i<=n;i++)val[i]=Read(),sum+=val[i],maxx=max(maxx,val[i]),cum[i]=cum[i-1]+val[i];
m=Read();
for(int i=1;i<=m;i++)
{
qry[i].k=Read();
qry[i].id=i;
}
divide(1,n,1,m);
for(int i=1;i<=m;i++)
{
if(ans[i]==-1)printf("Impossible\n");
else
printf("%d\n",ans[i]);
}
}
二分加前缀和
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N = 2E5 + 10;
int a[N], res[N * 10], s[N];
int n;
int fact(int t) { //结果往右
int cou = 0;
int L = 1, R = n; //操作区间[L, R]
int l = 1, r = n; //二分可能结果[l, n]
while (L < R) {
cou++;
while (l < r) {
const int mid = l + r + 1 >> 1;
if (s[mid] - s[L - 1] <= t) l = mid;
else r = mid - 1;
}
r = n; L = l + 1; l = L; //区间更新
}
if (L == R) cou++; //最后一个数单成区间
return cou;
}
int main(void)
{
cin >> n;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
s[i] = s[i - 1] + a[i];
}
const int max_ = *max_element(a + 1, a + 1 + n);
int q; cin >> q;
while (q--) {
int t; scanf("%d", &t);
if (t < max_) { printf("Impossible\n"); continue; } //不可二分, 无解
if (!res[t]) res[t] = fact(t); //如果t相同就直接输出结果
printf("%d\n", res[t]);
}
return 0;
}