先算出每一段蛋糕的长度,每次询问在原序列上二分查找或双指针即可。
时间复杂度
O
(
N
+
Q
)
O(N+Q)
O(N+Q),空间复杂度
O
(
N
)
O(N)
O(N)
#include<stdio.h>
#include<algorithm>
int a[200001];
long long sum[200001];
int main(){
int n,q,d;
scanf("%d",&n);
for(register int i=1;i<=n;i++){
scanf("%d",a+i);
sum[i]=1;
while((a[i]&1)==0){
a[i]>>=1;
sum[i]<<=1;
}
sum[i]+=sum[i-1];
}
scanf("%d",&q);
for(register int i=0;i!=q;i++){
long long x;
scanf("%lld",&x);
d=std::lower_bound(sum+1,sum+n+1,x)-sum;
printf("%d\n",a[d]);
}
return 0;
}
要最小值最大,二分答案。
根据二分出的答案,可以算出每门课需要翘课的数量或可以翘课的数量,检查课时是否足够即可。
时间复杂度
O
(
N
(
log
2
M
+
log
2
A
)
)
O(N(\log_2M+\log_2A))
O(N(log2M+log2A)),空间复杂度
O
(
N
)
O(N)
O(N)
#include<stdio.h>
#define R register int
#define L long long
int a[300000],b[300000];
inline bool Check(int n,int m,L x){
L tot=(L)n*m;
for(R i=0;i!=n;i++){
if(a[i]>b[i]){
L t=(x+a[i]-1)/a[i];
if(t>m){
L v=x-(L)m*a[i];
tot-=(v+b[i]-1)/b[i]+m;
}else{
tot-=t;
}
}else{
tot-=(x+b[i]-1)/b[i];
}
if(tot<0){
return false;
}
}
return true;
}
int main(){
int n,m,ct;
scanf("%d%d",&n,&m);
for(R i=0;i!=n;i++){
scanf("%d",a+i);
}
for(R i=0;i!=n;i++){
scanf("%d",b+i);
}
L l=1,r=1000000000000000000,mid,ans;
while(l<=r){
mid=l+r>>1;
if(Check(n,m,mid)==true){
ans=mid;
l=mid+1;
}else{
r=mid-1;
}
}
printf("%lld",ans);
return 0;
}
先对州按B排序,然后最终的抉择一定是先从小到大选一些州的B,然后选一些州的A。注意到选出的州一定是排序后的一段前缀和后面一些零散的A。
设状态
f
i
,
j
f_{i,j}
fi,j 表示前
i
i
i 个州选择
j
j
j 个B州的最小时间,再在外层枚举最终选了几个B州即可转移和更新答案案。
时间复杂度
O
(
N
3
)
O(N^3)
O(N3),空间复杂度
O
(
N
)
O(N)
O(N)
#include<stdio.h>
#include<algorithm>
#define R register int
#define D double
#define I inline
#define INF 999999999
I void Min(D&x,const D y){
if(x>y){
x=y;
}
}
struct State{
int ValA,ValB;
I void Read(){
scanf("%d%d",&ValA,&ValB);
if(ValB==-1){
ValB=INF;
}
}
I friend bool operator<(State A,State B){
return A.ValB<B.ValB;
}
}s[501];
D f[501],g[501];
int suf[502][501];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(R i=1;i<=n;i++){
s[i].Read();
}
std::sort(s+1,s+n+1);
for(R i=n;i!=0;i--){
for(R j=n-i+1;j!=0;j--){
suf[i][j]=suf[i+1][j-1]+s[i].ValA;
}
for(R j=1;j<=n-i;j++){
if(suf[i+1][j]<suf[i][j]){
suf[i][j]=suf[i+1][j];
}
}
}
D ans=suf[1][m];
for(R i=1;i<=m;i++){
D inv=1/(1.0+i);
f[0]=0;
for(R j=1;j<=n&&j<=m;j++){
for(R k=0;k<=j&&k<=i;k++){
g[k]=INF;
}
for(R k=0;k!=j&&k<=i;k++){
Min(g[k],f[k]+inv*s[j].ValA);
Min(g[k+1],f[k]+s[j].ValB/(1.0+k));
}
for(R k=0;k<=j&&k<=i;k++){
f[k]=g[k];
}
if(j>=i){
Min(ans,f[i]+inv*suf[j+1][m-j]);
}
}
}
printf("%.9lf",ans);
return 0;
}
借助线段树处理出ST表
f
i
,
j
,
k
f_{i,j,k}
fi,j,k 表示从
i
i
i 到
i
+
2
j
−
1
i+2^j-1
i+2j−1 中的一个位置出发乘坐
2
k
2^k
2k 班车能到达的区间即可。
时间复杂度
O
(
N
log
2
2
N
+
Q
log
2
N
)
O(N \log_2^2N+Q \log_2N)
O(Nlog22N+Qlog2N),空间复杂度
O
(
N
log
2
2
N
)
O(N \log_2^2N)
O(Nlog22N)
#include<stdio.h>
#define R register int
#define I inline
#define N 100001
I void Min(int&x,const int y){
if(x>y){
x=y;
}
}
I void Max(int&x,const int y){
if(x<y){
x=y;
}
}
struct Segment{
int Lf,Rt;
I friend Segment operator+(Segment A,Segment B){
Min(A.Lf,B.Lf);
Max(A.Rt,B.Rt);
return A;
}
}f[17][N],g[17][17][N];
I auto Pair(int l,int r){
Segment Res;
Res.Lf=l;
Res.Rt=r;
return Res;
}
class SegmentTree{
int MinV[400000],MaxV[400000],Len;
I void InitTree(int p,int lf,int rt){
if(lf==rt){
MinV[p]=MaxV[p]=lf;
}else{
MinV[p]=N;
InitTree(p<<1,lf,lf+rt>>1);
InitTree(p<<1|1,lf+rt+2>>1,rt);
}
}
I void Cover(int p,int lf,int rt,const int l,const int r,const int vl,const int vr){
if(l<=lf&&rt<=r){
Min(MinV[p],vl);
Max(MaxV[p],vr);
}else{
int mid=lf+rt>>1;
if(l<=mid){
Cover(p<<1,lf,mid,l,r,vl,vr);
}
if(r>mid){
Cover(p<<1|1,mid+1,rt,l,r,vl,vr);
}
}
}
I void GetAns(int p,int lf,int rt,const int x,Segment&Res){
Res=Res+Pair(MinV[p],MaxV[p]);
if(lf!=rt){
int mid=lf+rt>>1;
if(x>mid){
GetAns(p<<1|1,mid+1,rt,x,Res);
}else{
GetAns(p<<1,lf,mid,x,Res);
}
}
}
public:
I void Init(const int n){
Len=n;
InitTree(1,1,n);
}
I void Modify(int lf,int rt,int vl,int vr){
Cover(1,1,Len,lf,rt,vl,vr);
}
I void GetSeg(int x,Segment&Res){
Res.Lf=Res.Rt=x;
GetAns(1,1,Len,x,Res);
}
}SEG;
I void BuildST(const int n,int t){
for(R i=1;i<=n;i++){
g[t][0][i]=f[t][i];
}
for(R i=1;1<<i<=n;i++){
for(R j=1;j<=n+1-(1<<i);j++){
g[t][i][j]=g[t][i-1][j]+g[t][i-1][j+(1<<i-1)];
}
}
}
int Log2[N];
I auto GetSegment(int t,int l,int r){
int p=Log2[r-l+1];
return g[t][p][l]+g[t][p][r-(1<<p)+1];
}
int main(){
int n,k,m,q,x,y,ans,l,r;
scanf("%d%d%d",&n,&k,&m);
for(R i=2;i<=n;i++){
Log2[i]=Log2[i>>1]+1;
}
k--;
SEG.Init(n);
for(R i=0;i!=m;i++){
scanf("%d%d",&x,&y);
if(x<y){
SEG.Modify(x,x+k<y?x+k:y,N,y);
}else{
SEG.Modify(x-k>y?x-k:y,x,y,0);
}
}
for(R i=1;i<=n;i++){
SEG.GetSeg(i,f[0][i]);
}
BuildST(n,0);
for(R i=1;1<<i<=n;i++){
for(R j=1;j<=n;j++){
x=f[i-1][j].Lf;
y=f[i-1][j].Rt;
f[i][j]=GetSegment(i-1,x,y);
}
BuildST(n,i);
}
scanf("%d",&q);
for(R i=0;i!=q;i++){
scanf("%d%d",&x,&y);
ans=1;
l=r=x;
for(R j=Log2[n];j!=-1;j--){
Segment S=GetSegment(j,l,r);
if(y<S.Lf||y>S.Rt){
ans+=1<<j;
l=S.Lf;
r=S.Rt;
}
}
Segment S=GetSegment(0,l,r);
if(y<S.Lf||y>S.Rt){
puts("-1");
}else{
printf("%d\n",ans);
}
}
return 0;
}
在选择的矩形区域连边,每个点向自己周围且在矩形内的权值最大且小于自己权值的点连边,然后统计矩形内边数即可。
每个点的连边情况和该点与边界的位置情况相关。一个点和每个边界的位置情况有距离为
0
,
1
0,1
0,1和不少于
2
2
2三种情况,四个方向共
81
81
81中情况。
枚举上下边界,左右边界处理时用前缀和优化。
如果
H
>
W
H>W
H>W 就交换两个方向即可。
时间复杂度
O
(
H
2
W
)
O(H^2W)
O(H2W),空间复杂度
O
(
H
W
)
O(HW)
O(HW)
#include<stdio.h>
#include<vector>
using namespace std;
#define R register int
#define I inline
const int DIR[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
I void Max(int&x,const int y){
if(x<y){
x=y;
}
}
I int Id(int a,int b,int c,int d){
return a+b*3+c*9+d*27;
}
vector<int>H[223],Sum[81][233];
I int GetMax(int x,int y,bool a,bool b,bool c,bool d){
int res=0;
if(a==true&&H[x][y+1]<H[x][y]){
res=H[x][y+1];
}
if(b==true&&H[x+1][y]<H[x][y]){
Max(res,H[x+1][y]);
}
if(c==true&&H[x][y-1]<H[x][y]){
Max(res,H[x][y-1]);
}
if(d==true&&H[x-1][y]<H[x][y]){
Max(res,H[x-1][y]);
}
return res;
}
I bool Check(int x,int y,int a,int b,int c,int d){
if(a!=0&&H[x][y]==GetMax(x,y+1,a==2,b!=0,true,d!=0)||b!=0&&H[x][y]==GetMax(x+1,y,a!=0,b==2,c!=0,true)||c!=0&&H[x][y]==GetMax(x,y-1,true,b!=0,c==2,d!=0)||d!=0&&H[x][y]==GetMax(x-1,y,a!=0,true,c!=0,d==2)){
return false;
}
return true;
}
I int GetSum(int t,int x,int y){
if(x<0||y<0){
return 0;
}
return Sum[t][x][y];
}
I int SumAll(int t,int lx,int rx,int ly,int ry){
return GetSum(t,rx,ry)-GetSum(t,rx,ly-1)-GetSum(t,lx-1,ry)+GetSum(t,lx-1,ly-1);
}
I int CalcAll(int lx,int rx,int ly,int ry){
int res=0;
if(rx<lx+3){
for(R i=lx;i<=rx;i++){
for(R j=ly;j<=ry;j++){
res+=SumAll(Id(ry-j,rx-i,j-ly,i-lx),i,i,j,j);
}
}
}else{
for(R i=ly;i<=ry;i++){
res+=SumAll(Id(ry-i,2,i-ly,0),lx,lx,i,i)+SumAll(Id(ry-i,2,i-ly,1),lx+1,lx+1,i,i)+SumAll(Id(ry-i,2,i-ly,2),lx+2,rx-2,i,i)+SumAll(Id(ry-i,1,i-ly,2),rx-1,rx-1,i,i)+SumAll(Id(ry-i,0,i-ly,2),rx,rx,i,i);
}
}
return res;
}
I int CalcColumn(int lx,int rx,int y,int ld,int rd){
if(rx<lx+3){
int res=0;
for(R i=lx;i<=rx;i++){
res+=SumAll(Id(rd,rx-i,ld,i-lx),i,i,y,y);
}
return res;
}
return SumAll(Id(rd,2,ld,0),lx,lx,y,y)+SumAll(Id(rd,2,ld,1),lx+1,lx+1,y,y)+SumAll(Id(rd,2,ld,2),lx+2,rx-2,y,y)+SumAll(Id(rd,1,ld,2),rx-1,rx-1,y,y)+SumAll(Id(rd,0,ld,2),rx,rx,y,y);
}
I int CalcPart(int lx,int rx,int ry){
int res=0;
if(rx<lx+3){
for(R i=lx;i<=rx;i++){
res+=SumAll(Id(2,rx-i,2,i-lx),i,i,0,ry);
}
}else{
res=SumAll(Id(2,2,2,0),lx,lx,0,ry)+SumAll(Id(2,2,2,1),lx+1,lx+1,0,ry)+SumAll(Id(2,2,2,2),lx+2,rx-2,0,ry)+SumAll(Id(2,1,2,2),rx-1,rx-1,0,ry)+SumAll(Id(2,0,2,2),rx,rx,0,ry);
}
return res;
}
int ct[100001];
int main(){
int n,m;
scanf("%d%d",&n,&m);
if(n<m){
for(R i=0;i!=n;i++){
H[i].resize(m);
for(R j=0;j!=m;j++){
scanf("%d",&H[i][j]);
}
}
}else{
for(R i=0;i!=m;i++){
H[i].resize(n);
}
for(R i=0;i!=n;i++){
for(R j=0;j!=m;j++){
scanf("%d",&H[j][i]);
}
}
int t=n;
n=m;
m=t;
}
for(R i=0;i!=81;i++){
for(R j=0;j!=n;j++){
Sum[i][j].resize(m);
}
}
long long ans=0;
for(R i=0;i!=n;i++){
for(R j=0;j!=m;j++){
for(R a=0;a!=3&&j+a!=m;a++){
for(R b=0;b!=3&&i+b!=n;b++){
for(R c=0;c!=3&&c<=j;c++){
for(R d=0;d!=3&&d<=i;d++){
Sum[Id(a,b,c,d)][i][j]=Check(i,j,a,b,c,d);
}
}
}
}
}
}
for(R i=0;i!=81;i++){
for(R j=0;j!=n;j++){
for(R k=0;k!=m;k++){
Sum[i][j][k]+=GetSum(i,j-1,k)+GetSum(i,j,k-1)-GetSum(i,j-1,k-1);
}
}
}
for(R i=0;i!=n;i++){
for(R j=i;j!=n;j++){
for(R k=0;k!=m;k++){
for(R l=0;l!=3&&l<=k;l++){
if(CalcAll(i,j,k-l,k)==1){
ans++;
}
}
}
vector<int>A;
for(R k=m-1;k>2;k--){
int x=CalcColumn(i,j,k-3,0,2)+CalcColumn(i,j,k-2,1,2),c=CalcPart(i,j,k-2),y;
y=CalcColumn(i,j,k,2,0)+CalcColumn(i,j,k-1,2,1);
A.push_back(y+c);
ct[y+c]++;
c+=1-x;
if(c>-1){
ans+=ct[c];
}
}
for(int T:A){
ct[T]=0;
}
}
}
printf("%lld",ans);
return 0;
}