标签:
今天看了看51nod发现有这样一个练习赛,就做了做。因为实力太弱想不出E题,各位神犇勿D。
不难发现若干线段[li,ri]的交就是[max(li),min(ri)],那么我们考虑枚举min(ri),将ri>=min(ri)的区间按顺序加入,这时我们显然应该选第k小的li来更新答案。这些操作用个堆就可以轻松维护了。
时间复杂度为O(NlogN)。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } typedef long long ll; const int maxn=100010; int n,k,m; struct Line { int l,r; bool operator < (const Line& ths) const {return r>ths.r;} }A[maxn]; priority_queue<int> Q; ll S[maxn]; int main() { n=read();k=read();m=read(); rep(i,1,n) S[i]=S[i-1]+read(); rep(i,1,m) A[i].l=read(),A[i].r=read(); sort(A+1,A+m+1); rep(i,1,k) Q.push(A[i].l); ll ans=max(0ll,S[A[k].r]-S[Q.top()-1]); rep(i,k+1,m) { if(Q.top()>A[i].l) Q.pop(),Q.push(A[i].l); ans=max(ans,S[A[i].r]-S[Q.top()-1]); } printf("%lld\n",ans); return 0; }
开始没有看清题目:“求出每个数在多少个包含其的区间中是中位数”,所以我们只需考虑长度为奇数的区间就可以了。
那么对于每个数x求出答案就是一个经典问题了,<x的Ai设为-1,=x的Ai设为0,>x的Ai设为1,然后求一下有多少区间和为0就可以了。
时间复杂度为O(N^2)。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=8010; int n,A[maxn],B[maxn],S[maxn*2]; int main() { n=read(); rep(i,1,n) A[i]=read(); rep(i,1,n) { rep(j,1,n) { if(A[i]==A[j]) B[j]=0; else if(A[i]>A[j]) B[j]=1; else B[j]=-1; B[j]+=B[j-1]; } int ans=0; memset(S,0,sizeof(S)); for(int j=1;j<=n;j+=2) { S[B[j-1]+n]++; ans+=S[B[j]+n]; } memset(S,0,sizeof(S)); for(int j=2;j<=n;j+=2) { S[B[j-1]+n]++; ans+=S[B[j]+n]; } printf("%d%c",ans,i==n?‘\n‘:‘ ‘); } return 0; }
f[i][j]=ΣΣf[i`][j`](i`>=i+1,j`>=j+1)
f[i+1][j]=ΣΣf[i`][j`](i`>i+1,j`>=j+1)
f[i][j+1]=ΣΣf[i`][j`](i`>=i+1,j`>j+1)
f[i][j]=f[i+1][j]+f[i][j+1]-{ΣΣf[i`][j`](i`>i+1,j`>j+1)}+f[i+1][j+1]
=f[i+1][j]+f[i][j+1]
然后坐标变换一下就转化成f[i][j]=f[i-1][j-1]+f[i-1][j]了,答案即为C(n+m-4,n-2)。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=getchar(); for(;!isdigit(c);c=getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=getchar()) x=x*10+c-‘0‘; return x*f; } typedef long long ll; const int maxn=1010; const int mod=1000000007; ll pow(ll n,int m) {ll ans=1;for(;m;m>>=1,(n*=n)%=mod) if(m&1) (ans*=n)%=mod;return ans;} int f[maxn][maxn]; ll C(int n,int m) { ll ans1=1,ans2=1; rep(i,n-m+1,n) (ans1*=i)%=mod; rep(i,1,m) (ans2*=i)%=mod; return ans1*pow(ans2,mod-2)%mod; } int main() { int n=read()-1,m=read()-1; printf("%lld\n",C(n+m-2,n-1)); return 0; }
对随机数据有这样一个性质:如果从位置1向后跳,每次跳到下一个值严格比这一个大的位置,期望跳O(logn)次就会终止。
所以我们可以枚举左端点,模拟右端点的跳跃同时维护当前[l,r]的Ai的最大值mx与最小值mn,用二分套ST表就可以O(logn)计算出下一个mx或mn值改变的位置,在这个区间内答案是不变的,只要在区间打上一个max标记就可以了,用线段树可以做到O(logn),因为总跳越次数为O(nlogn),时间复杂度为O(nlog^2n)。
但这道题有点卡常数,进一步观察得到答案是随长度不增的,所以更新答案时只需要前缀打个标记就行了,这样就可以省掉线段树的常数了。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-‘0‘; return x*f; } typedef long long ll; const int maxn=100010; const int inf=2000000000; int n,A[maxn]; int Log[maxn],minv[20][maxn],maxv[20][maxn]; void init() { Log[0]=-1;rep(i,1,n+1) Log[i]=Log[i>>1]+1; rep(i,1,n) minv[0][i]=maxv[0][i]=A[i]; minv[0][n+1]=-inf;maxv[0][n+1]=inf; for(int j=1;(1<<j)<=n+1;j++) for(int i=1;i+(1<<j)<=n+2;i++) { minv[j][i]=min(minv[j-1][i],minv[j-1][i+(1<<j-1)]); maxv[j][i]=max(maxv[j-1][i],maxv[j-1][i+(1<<j-1)]); } } int query(int l,int r,int t) { int k=Log[r-l+1]; if(!t) return min(minv[k][l],minv[k][r-(1<<k)+1]); return max(maxv[k][l],maxv[k][r-(1<<k)+1]); } int getmn(int l,int val) { int r=n+1,mid,p=l; while(l<r) if(query(p,mid=l+r>>1,0)<val) r=mid; else l=mid+1; return l; } int getmx(int l,int val) { int r=n+1,mid,p=l; while(l<r) if(query(p,mid=l+r>>1,1)>val) r=mid; else l=mid+1; return l; } ll ans[maxn]; int main() { n=read();rep(i,1,n) A[i]=read(); init();int cnt=0; rep(l,1,n) { int mx=A[l],mn=A[l],r=l; while(r<=n) { int p=min(getmn(r+1,mn),getmx(r+1,mx)); cnt++;ans[p-l]=max(ans[p-l],(ll)mx*mn); r=p;mn=min(mn,A[r]);mx=max(mx,A[r]); } } dwn(i,n,1) ans[i]=max(ans[i],ans[i+1]); rep(i,1,n) printf("%lld\n",ans[i]); return 0; }
设传送站分别设在x和y,且x<y。
考虑二分答案ans,将所有R[i]-L[i]>ans的路线拿出来,那么|L[i]-x|+|R[i]-y|<=ans。
将所有的(L[i],R[i])作为平面的点,那么问题就转化成在平面中寻找一个点P,满足P到其他的点的曼哈顿距离均<=ans。
坐标变换一下(将(x,y)变换成(x-y,x+y))将曼哈顿距离转化成切比雪夫距离,然后直接维护矩形交就行了。
时间复杂度为O(NlogN)。
#include<cstdio> #include<cctype> #include<queue> #include<cstring> #include<algorithm> #define rep(i,s,t) for(int i=s;i<=t;i++) #define dwn(i,s,t) for(int i=s;i>=t;i--) #define ren for(int i=first[x];i;i=next[i]) using namespace std; const int BufferSize=1<<16; char buffer[BufferSize],*head,*tail; inline char Getchar() { if(head==tail) { int l=fread(buffer,1,BufferSize,stdin); tail=(head=buffer)+l; } return *head++; } inline int read() { int x=0,f=1;char c=Getchar(); for(;!isdigit(c);c=Getchar()) if(c==‘-‘) f=-1; for(;isdigit(c);c=Getchar()) x=x*10+c-‘0‘; return x*f; } const int maxn=500010; const int inf=1e9; int n,m,L[maxn],R[maxn]; int check(int d) { int x1=-inf,y1=-inf,x2=inf,y2=inf; rep(i,1,m) if(R[i]-L[i]>d) { int X1=L[i]-R[i]-d,Y1=L[i]+R[i]-d,X2=L[i]-R[i]+d,Y2=L[i]+R[i]+d; if(x2<X1||x1>X2) return 0; else x1=max(x1,X1),x2=min(x2,X2); if(y2<Y1||y1>Y2) return 0; else y1=max(y1,Y1),y2=min(y2,Y2); } return 1; } int main() { n=read();m=read();int l=0,r=n,mid; rep(i,1,m) { L[i]=read();R[i]=read(); if(L[i]>R[i]) swap(L[i],R[i]); } while(l<r) if(check(mid=l+r>>1)) r=mid; else l=mid+1; printf("%d\n",l); return 0; }
标签:
原文地址:http://www.cnblogs.com/wzj-is-a-juruo/p/5528249.html