牛客练习赛96(未完工)
作者:互联网
A.小y的平面
签到题,存点然后排序。一定满足 Xi<=Xi+1且Yi<=Yi+1。若不满足直接输出No,否则输出Yes。
#include<bits/stdc++.h> using namespace std; struct node { int x,y; }t[1000006]; bool cmp(node a,node b) { if(a.x==b.x) return a.y<b.y; return a.x<b.x; } int main() { int n,xx=0,yy=0; cin>>n; for(int i=0;i<n;i++) cin>>t[i].x>>t[i].y; sort(t,t+n,cmp); for(int i=0;i<n;i++) { if(xx<=t[i].x&&yy<=t[i].y) { xx=t[i].x; yy=t[i].y; } else { puts("NO"); return 0; } } puts("YES"); return 0; }View Code
B.小y的树
计数题,统计每条边的边权。对于一颗树来说,选择任意一条边并将其砍断,可以将树分成两部分,其中一部分仍然是个满k叉树,另一部分不是。我们可以发现满k叉树每一层的节点树为k0,k1,...kn-1。
所以对于链接第i层和第i+1层的边,砍断以后会得到一颗n-i层的树(1<=i<n),所以很容易计算得到较小部分的节点数量a,较大部分的节点数量用总数减a即可。从两颗树中间任意取一个点,这两个点的路径都会经过砍断的这条边。所以对于这条边的贡献是a*b。由满k叉树的对称性,同一层的边具有相同的权值。不难推出,链接第i层和第i+1层的边有m=ki条。所以这一层所有边的权和为a*b*m.
由于数据规模较大,我们存储节点数量的时候需要mod1e9+7,这时可能导致sum-a是个负数。为了避免这种情况,计算时要算(sum-a)%mod+mod。
#include<bits/stdc++.h> using namespace std; #define int long long const int mod=1e9+7; int f[1000006]; int v[1000006]; signed main() { int n,k,ans=0; cin>>n>>k; //从第0层到第n-1层,共有n层,每层有k^n个节点 v[1]=f[1]=1; //f[i]存深度为i的k叉树有多少个节点 for(int i=2;i<=n;i++) { v[i]=v[i-1]*k%mod;//第i层有这么多个点 f[i]=(f[i-1]+v[i])%mod;//i层的树有这么多点 } for(int i=1;i<n;i++)//从第一层到第n层统计边 { int a=f[i]; int b=(f[n]-a)%mod+mod; int m=v[n-i+1]; ans=(ans+a*b%mod*m%mod)%mod; } cout<<ans<<endl; }View Code
C.小y的序列
计数题,二分,st表。
对于固定的左端点L,[L,L]....[L,N]这些区间的max是非递减的,min是非递增的。所以max-min保持了单调性。在这个存在单调性的序列中,用二分找到满足题意的最左点r1和最右点r2,即对于任意的R∈[r1,r2],[L,R]都满足题意。那么左端点L对答案的贡献即为r2-r1+1。
然后从1到n枚举左端点即可。在二分时不断查询[l,mid]的最大值和最小值。
对于RMQ问题,一般是采用线段树来完成O(log)查找。但是这题数据规模1e6卡了2log,并且是静态区间最值问题,所以可以改用ST表来维护静态区间最值。ST表可以实现O(1)查找,效率要高不少。
/*刚发现有人线段树也过了,一会研究一下。*/
巨佬用的线段树+双指针1log过的,确实妙。到时候补一下双指针(大弱项qwq
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+6; int n,k,a[maxn]; long long ans=0; struct node { int l,r,maxx,minn; }t[maxn<<2]; void build(int k,int l,int r) { t[k].l=l,t[k].r=r; if(l==r) { t[k].maxx=t[k].minn=a[l]; return; } int mid=(t[k].l+t[k].r)/2; build(k<<1,l,mid); build(k<<1|1,mid+1,r); t[k].maxx=max(t[k<<1].maxx,t[k<<1|1].maxx); t[k].minn=min(t[k<<1].minn,t[k<<1|1].minn); } int query_max(int k,int l,int r) { if(l<=t[k].l&&t[k].r<=r) return t[k].maxx; int mid=(t[k].l+t[k].r)/2; int ans=0; if(l<=mid) ans=max(ans,query_max(k<<1,l,r)); if(mid<r) ans=max(ans,query_max(k<<1|1,l,r)); return ans; } int query_min(int k,int l,int r) { if(l<=t[k].l&&t[k].r<=r) return t[k].minn; int mid=(t[k].l+t[k].r)/2; int ans=10000006; if(l<=mid) ans=min(ans,query_min(k<<1,l,r)); if(mid<r) ans=min(ans,query_min(k<<1|1,l,r)); return ans; } int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); for(int i=1;i<=n;i++) { long long l=i,r=n; while(l<r) { long long mid=(l+r)>>1; if(query_max(1,i,mid)-query_min(1,i,mid)>=k) r=mid; else l=mid+1; } if(query_max(1,i,l)-query_min(1,i,l)==k) { long long ll=i,rr=n; while(ll<rr) { long long mid=(ll+rr+1)>>1; if(query_max(1,i,mid)-query_min(1,i,mid)<=k) ll=mid; else rr=mid-1; } ans+=ll-l+1; } } printf("%lld\n",ans); }线段树TLE
#include<bits/stdc++.h> using namespace std; const int N=1e6+10,M=21; int n,k,a[N],stn[N][M],stx[N][M]; int lg[N]; void init() { for(int i=1;i<M;i++) for(int j=1;j+(1<<i)-1<=n;j++) { stx[j][i]=max(stx[j][i-1],stx[j+(1<<(i-1))][i-1]); stn[j][i]=min(stn[j][i-1],stn[j+(1<<(i-1))][i-1]); } for(int i=2;i<=n;i++) lg[i]=lg[i>>1]+1; } int qurey(int l,int r) { int t=lg[r-l+1]; return max(stx[l][t],stx[r-(1<<t)+1][t])-min(stn[l][t],stn[r-(1<<t)+1][t]); } signed main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>k; for(int i=1;i<=n;i++) { cin>>stx[i][0]; stn[i][0]=stx[i][0]; } init(); long long ans=0; for(int i=1;i<=n;i++) { int l=i,r=n; while(l<r) { int mid=(l+r)>>1; if(qurey(i,mid)>=k) r=mid; else l=mid+1; } int z=r; if(qurey(i,z)!=k) continue; l=i,r=n; while(l<r) { int mid=(l+r+1)>>1; if(qurey(i,mid)<=k) l=mid; else r=mid-1; } ans=ans+l-z+1; } cout<<ans; return 0; }ST表AC
DEF待补
标签:练习赛,int,max,mid,long,牛客,query,stx,96 来源: https://www.cnblogs.com/brucekz/p/15935402.html