牛客网round1
题解:
1.
二分答案之后判断
把式子移项使得x,y不关联
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) const int N=3e5; int a[N],sum[N],n,m; const int INF=1e9; bool check(int x) { sum[0]=0; int mina=-INF; rep(i,1,n) { if (a[i]<x) sum[i]=sum[i-1]+1; else sum[i]=sum[i-1]; if (i-m+1>0) mina=max(mina,2*sum[i-m]-(i-m+1)); if (2*sum[i]-i<=mina) return(1); } return(0); } int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); cin>>n>>m; rep(i,1,n) cin>>a[i]; int h=0,t=INF; while (h<t) { int mid=(h+t+1)>>1; if (check(mid)) h=mid; else t=mid-1; } cout<<h<<endl; return 0; }
2.
数位dp
考虑10个数字一共有18个
C(27,9) 算一下发现不大
然后就直接记忆化搜索就行了
数比较大可以用map记录
但好像比较慢于是改了hash
然后有3个点是考细节的
后面两个是map如果初值为0就炸了 可能之后一直为0 因为y可以是-1
另外一个是0要特殊考虑dfs(0)
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define ll long long #define mp(x,y) make_pair(x,y) ll l,n,m,f[100]; int cnt=0; const int mo=6e6+7; struct re{ bool a,b; short c; ll d,ans; }hs[mo+1000]; queue<int> q; struct hash{ ll find(bool a,bool b,short x,ll y) { int t1=((1ll*x%mo*y%mo)%mo+mo)%mo; while (hs[t1].c&&!(hs[t1].a==a&&hs[t1].b==b&&hs[t1].c==x&&hs[t1].d==y)) t1++,cnt++; if (hs[t1].c) return(hs[t1].ans); return(-1); } void insert(bool a,bool b,short x,ll y,ll ans) { int t1=((1ll*x%mo*y%mo)%mo+mo)%mo; while (hs[t1].c) t1++,cnt++; hs[t1].a=a; hs[t1].b=b; hs[t1].c=x; hs[t1].d=y; hs[t1].ans=ans; q.push(t1); } void clear() { while (!q.empty()) { int x=q.front(); q.pop(); hs[x].c=hs[x].ans=0; } } }M; ll dfs(short x,ll y,bool z,bool kk) { cnt++; ll ans1=M.find(z,kk,x,y); if (ans1!=-1) return(ans1); if (x==l+1) { if (kk==1) y=0; if (y<=m) { return(1); } return(0); } ll ans=0; rep(i,0,9) if (i==0&&kk==1) ans+=dfs(x+1,1,0,1); else { if (z==1) { if (i<f[x]) ans+=dfs(x+1,y*i,0,0); if (f[x]==i) ans+=dfs(x+1,y*i,1,0); } else ans+=dfs(x+1,y*i,0,0); } M.insert(z,kk,x,y,ans); return(ans); } ll js(ll x,ll y) { if (x<0) return(0); M.clear(); ll tmp=x; l=0; if (x==0) l=1,f[1]=0; while (tmp) l++,f[l]=tmp%10,tmp/=10; reverse(f+1,f+l+1); m=y; return dfs(1,1,1,1); } int main() { ios::sync_with_stdio(false); ll x1,x2,y1,y2; cin>>x1>>x2>>y1>>y2; cout<<js(x2,y2) -js(x2,y1-1)- (js(x1-1,y2)- js(x1-1,y1-1))<<endl; return 0; }
3.
大体思路就是差分来做
刚开始傻逼的写了直接dfs拿线段树来维护。。
这样显然是有问题的。。。
并且,我的树上二分也很傻比。。。
取了比它深度浅的二分所以既要多写代码又要多写细节。。
拍完了细节才发现要改成线段树合并
5min改完就a了。。
另外一种做法是主席树+二分 二分部分和这种做法一样
主席树就是维护dfs序也和这个基本一样
利用相减表示出当前子树
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define mid ((h+t)>>1) const int N=3e5; int head[N],l,dep[N],bz[N][20],ans[N]; vector<int> ve[N],ve3[N]; struct re{ int a,b; }a[N*2]; vector<re> ve2[N]; void arr(int x,int y) { a[++l].a=head[x]; a[l].b=y; head[x]=l; } void dfs(int x,int y) { bz[x][0]=y; dep[x]=dep[y]+1; for (rint u=head[x];u;u=a[u].a) { rint v=a[u].b; if (v!=y) dfs(v,x); } } int lca(int x,int y) { if (dep[x]<dep[y]) swap(x,y); dep(i,19,0) if (dep[bz[x][i]]>=dep[y]) x=bz[x][i]; if (x==y) return(x); dep(i,19,0) if (bz[x][i]!=bz[y][i]) x=bz[x][i],y=bz[y][i]; return(bz[x][0]); } int f[N],ph[N],pt[N],num,n,m,root[N]; struct sgt{ int v[N*20],ls[N*20],rs[N*20],cnt; #define updata(x) v[x]=v[ls[x]]+v[rs[x]] void change(int &x,int h,int t,int pos,int k) { if (pos<=0) return; if (!x) x=++cnt; if (h==t) { v[x]+=k; return; } if (pos<=mid) change(ls[x],h,mid,pos,k); else change(rs[x],mid+1,t,pos,k); updata(x); } int query(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) return(v[x]); int ans=0; if (h1<=mid) ans+=query(ls[x],h,mid,h1,t1); if (mid<t1) ans+=query(rs[x],mid+1,t,h1,t1); return(ans); } void find(int x,int h,int t,int h1,int t1) { if (h1<=h&&t<=t1) { f[++num]=x; ph[num]=h; pt[num]=t; return; } if (h1<=mid) find(ls[x],h,mid,h1,t1); if (mid<t1) find(rs[x],mid+1,t,h1,t1); } int find2(int x,int h,int t,int k) { if (h==t) { if (v[x]>=k) return(h); else return(h+1); } if (v[rs[x]]<k) return(find2(rs[x],mid+1,t,k)); else return(find2(ls[x],h,mid,k-v[rs[x]])); } int query2(int kk,int x,int y) { int k1=y-query(kk,1,n,dep[x]+1,n); num=0; find(kk,1,n,1,dep[x]); dep(i,num,1) { if (v[f[i]]>=k1) k1-=v[f[i]]; else return(find2(f[i],ph[i],pt[i],k1)); } return(1); } int merge(int x,int y) { if (!x||!y) return(x|y); v[x]+=v[y]; ls[x]=merge(ls[x],ls[y]); rs[x]=merge(rs[x],rs[y]); return(x); } }S; void dfs2(int x,int y) { for (rint u=head[x];u;u=a[u].a) { rint v=a[u].b; if (v!=y) dfs2(v,x),root[x]=S.merge(root[x],root[v]); } int l=(int)(ve3[x].size())-1; rep(i,0,l) { S.change(root[x],1,n,dep[x],1); S.change(root[x],1,n,dep[ve3[x][i]]-1,-1); } l=(int)(ve2[x].size())-1; rep(i,0,l) { int x1=ve2[x][i].a,y1=ve2[x][i].b; ans[x1]=dep[x]-S.query2(root[x],x,y1); } l=(int)(ve[x].size())-1; rep(i,0,l) { S.change(root[x],1,n,dep[x]-1,1); S.change(root[x],1,n,dep[ve[x][i]],-1); } } int main() { ios::sync_with_stdio(false); cin>>n>>m; rep(i,1,n-1) { int x,y; cin>>x>>y; arr(x,y); arr(y,x); } dfs(1,0); rep(i,1,19) rep(j,1,n) bz[j][i]=bz[bz[j][i-1]][i-1]; rep(i,1,m) { int x,y; cin>>x>>y; int k=lca(x,y); ve[k].push_back(x); ve[k].push_back(y); ve3[x].push_back(k); ve3[y].push_back(k); } int q; cin>>q; rep(i,1,q) { int x,t; cin>>x>>t; ve2[x].push_back((re){i,t}); } dfs2(1,0); rep(i,1,q) cout<<max(0,ans[i])<<endl; return 0; }