Rank38。
还是比较不满意吧,C卡了太久,E没调出来,D也没空去做了。
A
签到题。
#include<bits/stdc++.h> using namespace std; #define ll long long const int N=100007; int x[N],y[N]; ll sqr(ll x){return 1ll*x*x;} ll dis(ll x,ll y,ll a,ll b){return sqr(x-a)+sqr(y-b);} int main() { ll ans=0,n,i,a,b,x,y,r; cin>>n>>a>>b>>r; for(i=1;i<=n;++i) { cin>>x>>y; if(dis(x,y,a,b)<=sqr(r)) ++ans; } cout<<ans; }
B
计算\(p,i,n\)分别最前能放在哪里,\(i,n,k\)最后能放在哪里。
#include<bits/stdc++.h> using namespace std; vector<int>pos[5]; const int N=1000007; char s[N];int n,mp[1001]; int Finda(int x) { int p=0; for(int i=1;i<=x;++i) { auto it=lower_bound(pos[i].begin(),pos[i].end(),p); if(it==pos[i].end()) return -1; p=pos[i][it-pos[i].begin()]; } return p; } int Findb(int x) { int p=n+1; for(int i=4;i>=x;--i) { auto it=upper_bound(pos[i].begin(),pos[i].end(),p); if(it==pos[i].begin()) return -1; it=prev(it); p=pos[i][it-pos[i].begin()]; } return p; } int main() { int T,i;scanf("%d",&T); mp['p']=1,mp['i']=2,mp['n']=3,mp['k']=4; while(T--) { scanf("%d%s",&n,s+1);int f=0,flg=0; for(i=1;i<=4;++i) pos[i].clear(); for(i=1;i<=n;++i) if(mp[s[i]]) pos[mp[s[i]]].push_back(i); for(i=1;i<=3;++i) { int p1=Finda(i); if(p1==-1) continue; int p2=Findb(i+1); if(p2==-1) continue; if(p2<p1) continue; f=max(f,p2-p1-1),flg=1; } if(!flg) puts("-1"); else printf("%d\n",f); } }
C
设\(f_i\)表示分界点为\(i\)的个数。
对于一次操作\((i,l,r)\)。
我们会在\(l-1,r\)将\(f\)加上\(2^{i-1}\)。
而\([1,l)\cup(r,n]\)这一部分不会变,所以\(f\)要\(*2\)。
#include<bits/stdc++.h> using namespace std; const int N=2007,P=20050321; int a[N]; int read(){int x;scanf("%d",&x);return x;} int inc(int a,int b){return a+=b,a>=P? a-P:a;} int mul(int a,int b){return 1ll*a*b%P;} int power(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;} int main() { int n=read(),m=read(),i,l,r,x,ans; a[0]=1; for(i=1;i<=m;++i) { l=read(),r=read(),x=power(2,i-1),ans=0; for(int i=0;i<l-1;++i) a[i]=inc(a[i],a[i]); for(int i=r+1;i<n;++i) a[i]=inc(a[i],a[i]); a[l-1]=inc(a[l-1],x),a[r]=inc(a[r],x); for(int i=0;i<n;++i) ans=inc(ans,a[i]); cout<<ans<<endl; } }
D
询问离线右端点升序排序。
用树状数组维护第\(x\)个操作的贡献。
查询就是简单的区间查询。
然后操作可以用珂朵莉树维护序列的极大连续子段,每次暴力修改同时维护树状数组。
#include<bits/stdc++.h> #define ll long long #define IT set<node>::iterator using namespace std; namespace IO { char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[19],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21); char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);} void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;} void Put(char x){*oS++=x;if(oS==oT)Flush();} int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;} void write(ll x){int top=0;if(!x)Put('0');while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put('\n');} } using namespace IO; const int N=500007; int n,m,Q;ll ans[N]; struct operation{int l,r,v;}opt[N]; struct query{int l,r,id;}q[N]; struct BIT { ll t[N]; void add(int p,ll v){if(!p)return;for(;p<=n;p+=p&-p)t[p]+=v;} ll ask(int p){ll s=0;for(;p;p^=p&-p)s+=t[p];return s;} ll query(int l,int r){return ask(r)-ask(l-1);} }bit; struct node{int l,r,x,id;node(int a=0,int b=0,int c=0,int d=0){l=a,r=b,x=c,id=d;}}; int operator<(node a,node b){return a.l<b.l;} set<node>s; IT split(int pos) { IT it=s.lower_bound(node(pos)); if(it!=s.end()&&it->l==pos) return it; --it; int L=it->l,R=it->r,X=it->x,ID=it->id; s.erase(it),s.insert(node(L,pos-1,X,ID)); return s.insert(node(pos,R,X,ID)).first; } void assign(int l,int r,int x,int id) { IT itr=split(r+1),itl=split(l); for(;itl!=itr;++itl,s.erase(prev(itl))) bit.add(itl->id,-1ll*((itl->r)-(itl->l)+1)*(itl->x)); s.insert(node(l,r,x,id)); bit.add(id,1ll*(r-l+1)*x); } int main() { n=read(),m=read(),Q=read();int i,j=1; for(i=1;i<=n;++i) opt[i]={read(),read(),read()}; for(i=1;i<=Q;++i) q[i]={read(),read(),i}; sort(q+1,q+Q+1,[](query a,query b){return a.r<b.r;}),s.insert(node(1,m,0,0)); for(i=1;i<=n;++i) { assign(opt[i].l,opt[i].r,opt[i].v,i); while(j<=Q&&q[j].r==i) ans[q[j].id]=bit.query(q[j].l,i),++j; } for(i=1;i<=Q;++i) write(ans[i]); return Flush(),0; }
E
先tarjan,然后在DAG上dp。(tarjan的scc的编号反序就是拓扑序)
具体的维护一下从\(1\)到每个scc的最短边,最长边和最大路径边权极差即可。
#include<bits/stdc++.h> #define pi pair<int,int> #define fi first #define se second #define pb push_back using namespace std; namespace IO { char ibuf[(1<<21)+1],*iS,*iT; char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);} int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;} } using namespace IO; int min(int a,int b){return a<b? a:b;} int max(int a,int b){return a>b? a:b;} const int N=200007,M=500007; vector<pi>G[N],E[N]; struct edge{int u,v,w;}e[M]; struct node{int mn,mx,ans;node(int a=0,int b=0,int c=0){mn=a,mx=b,ans=c;}}f[N]; int n,m,Q,dfn[N],low[N],Time,stk[N],top,cnt,vis[N],bel[N],mx[N],mn[N]; node merge(node a,node b) { a.ans=max(max(max(a.ans,b.ans),a.mx-b.mn),b.mx-a.mn); a.mx=max(a.mx,b.mx); a.mn=min(a.mn,b.mn); return a; } void tarjan(int u) { dfn[u]=low[u]=++Time,stk[++top]=u,vis[u]=1; for(pi x:G[u]) { int v=x.fi; if(!dfn[v]) tarjan(v),low[u]=min(low[u],low[v]); else if(vis[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]) { ++cnt; while(stk[top+1]^u) bel[stk[top]]=cnt,vis[stk[top--]]=0; } } int main() { n=read(),m=read(),Q=read(),memset(mn,0x3f,sizeof mn); for(int i=1,u,v,w;i<=m;++i) u=read(),v=read(),w=read(),e[i]=(edge){u,v,w},G[u].pb(pi(v,w)); tarjan(1); for(int i=1;i<=n;++i) if(bel[i]) bel[i]=cnt+1-bel[i]; for(int i=1,id;i<=m;++i) if(bel[e[i].u]&&bel[e[i].v]) if(bel[e[i].u]==bel[e[i].v]) id=bel[e[i].u],mn[id]=min(mn[id],e[i].w),mx[id]=max(mx[id],e[i].w); else E[bel[e[i].v]].pb(pi(bel[e[i].u],e[i].w)); for(int u=1;u<=cnt;++u) { node s=f[u]=node(mn[u],mx[u],mx[u]-mn[u]); for(pi x:E[u]) { int v=x.fi,w=x.se; node t=merge(s,merge(node(w,w,0),f[v])); f[u]=node(min(f[u].mn,t.mn),max(f[u].mx,t.mx),max(f[u].ans,t.ans)); } } for(int u;Q;--Q) { u=read(); if(!bel[u]||f[bel[u]].ans<0) puts("-1"); else printf("%d\n",f[bel[u]].ans); } }