2024杭电第三场
打了个爽!今天打得很稳,基本没有罚时,相当优雅的一场
1002 旅行
线段树合并经典题,顺便在过程中做个dp
#include<bits/stdc++.h> using namespace std; const int N = 2e5+5; #define mid ((l+r)>>1) typedef long long ll; vector<int>e[N]; int tot,n,c[N],w[N],root[N]; ll nowsum,g[N]; struct seg_tree{ int l,r; ll tag,sum; }t[N<<6]; void up(int rt){ int ls=t[rt].l,rs=t[rt].r; if(ls) t[rt].sum=max(t[rt].sum,t[ls].sum); if(rs) t[rt].sum=max(t[rt].sum,t[rs].sum); } void down(int rt){ if(t[rt].tag==0) return; int ls=t[rt].l,rs=t[rt].r; if(ls)t[ls].tag+=t[rt].tag,t[ls].sum+=t[rt].tag; if(rs)t[rs].tag+=t[rt].tag,t[rs].sum+=t[rt].tag; t[rt].tag=0; } void add(int &rt,int l,int r,int x,int val){ if(!rt) rt=++tot,t[rt].tag=t[rt].l=t[rt].r=t[rt].sum=0; if(l==r){ t[rt].tag=0; t[rt].sum=val; return; } if(x<=mid) add(t[rt].l,l,mid,x,val); else add(t[rt].r,mid+1,r,x,val); up(rt); } int merge(int x,int y,int l,int r,ll &ans){ if(!x || !y) return x+y; if(l==r){ ans=max(ans,1ll*nowsum+t[x].sum+t[y].sum); t[x].sum=max(t[x].sum,t[y].sum); return x; } down(x),down(y); t[x].l=merge(t[x].l,t[y].l,l,mid,ans); t[x].r=merge(t[x].r,t[y].r,mid+1,r,ans); up(x); return x; } void dfs(int u,int fa){ // cout<<u<<" "<<fa<<"\n"; ll sum=0; for(auto v:e[u]){ if(v==fa) continue; dfs(v,u); sum+=g[v]; } g[u]=sum; nowsum=sum; add(root[u],1,n,c[u],w[u]); for(auto v:e[u]){ if(v==fa) continue; t[root[v]].sum-=g[v]; t[root[v]].tag-=g[v]; root[u]=merge(root[u],root[v],1,n,g[u]); } // cout<<u<<" over "<<"\n"; t[root[u]].tag+=sum; t[root[u]].sum+=sum; } void solve(){ cin>>n; for(int i=1;i<=n;i++) cin>>c[i]; for(int i=1;i<=n;i++) cin>>w[i]; for(int i=1,u,v;i<n;i++){ cin>>u>>v;e[u].push_back(v);e[v].push_back(u); } dfs(1,0); cout<<g[1]<<"\n"; for(int i=1;i<=tot;i++) t[i]=(seg_tree){0,0,0,0}; for(int i=1;i<=n;i++){ root[i]=0; g[i]=0; e[i].clear(); } tot=0; } int main(){ //freopen("Test.in","r",stdin); ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t;cin>>t; while(t--){ solve(); } return 0; }
1001
考虑递推,发现答案和因子有关,再加上森林里只有一棵树的情况 ( i个节点构成的树的种数为f[i-1] )
#include<bits/stdc++.h> using namespace std; const int N=1e6,mod=998244353; inline int add(int x,int y){return (x+=y)>=mod?x-mod:x;} int n,f[N+5],g[N+5]; void Kafka() { cin>>n; f[0]=g[0]=1; for(int i=1;i<=n;++i) { g[i]=f[i-1]; for(int j=1;i*j<=n;++j) f[i*j]=add(f[i*j],g[i]); cout<<f[i]; if(i==n) cout<<endl; else cout<<' '; } } signed main() { Kafka(); return 0; }
1012
题意转化为两个条件都不能满足,则
1. 实力>=L 的队伍只能有一支
2. 队内极差要超过D
分类讨论:
如果a1的实力>=L,那么只能找<L的,且为了构造极差,最好找最小值。判断个数够不够
如果a1的实力<L,那么为了构造极差,可以把最大值放进来,再把最小的放进来。同样判断个数够不够
实现的话自认为我的代码还是优雅的👉👈
有个小trick是单独把a1先拿出来
#include<bits/stdc++.h> using namespace std; const int N = 2e5+5; int a[N]; void solve(){ int n,l,d,a1;cin>>n>>l>>d; cin>>a1; n--; for(int i=1;i<=n;i++) cin>>a[i]; sort(a+1,a+n+1); if(a1>=l){ int cnt=0; for(int i=1;i<=n;i++){ if(a[i]<l) cnt++; } if(cnt>=3&&a1-a[1]>d) { cout<<"Yes"<<"\n"; } else cout<<"No"<<"\n"; } else { int cnt=0; int tmp[5]={0}; for(int i=1;i<=n-1;i++){ if(a[i]<l){ cnt++;tmp[cnt]=a[i]; } if(cnt==2) break; } if(cnt<2) { cout<<"No"<<"\n"; return; } cnt++;tmp[cnt]=a1; cnt++;tmp[cnt]=a[n]; sort(tmp+1,tmp+cnt+1); if(tmp[4]-tmp[1]>d) cout<<"Yes"<<"\n"; else cout<<"No"<<"\n"; } } int main(){ ios_base::sync_with_stdio(false); cin.tie(0);cout.tie(0); int t;cin>>t; while(t--){ //TODO solve(); } }
1007 单峰数列
区间加用差分
如果 [l,r] 是递增数列则 [l+1,r]的差分值应该都>0
如果 [l,r] 是递减数列则 [l+1,r]的差分值应该都<0
如果 [l,r] 是相等则 [l+1,r]的差分值应该都=0
线段树维护区间为0的个数、为正数的个数、为负数的个数即可
至于第5个询问,观察到 n<=1e5 ,可以先二分出递增序列的右端点ans,再检查 [ans+1,r]是否为递减数列,O(nloglog),能过
#include<bits/stdc++.h> using namespace std; inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } const int N = 1e5+100; #define ls (rt<<1) #define rs (rt<<1|1) #define mid ((l+r)>>1) typedef long long ll; ll a[N],c[N]; int n; struct seg_tree{ int zero,neg,posi; }t[N<<2]; void up(int rt){ t[rt].neg=t[ls].neg+t[rs].neg; t[rt].posi=t[ls].posi+t[rs].posi; t[rt].zero=t[ls].zero+t[rs].zero; } void uppoint(int rt,int l){ t[rt].neg=t[rt].posi=t[rt].zero=0; if(c[l]==0) t[rt].zero++; if(c[l]>0) t[rt].posi++; if(c[l]<0) t[rt].neg++; } void build(int rt=1,int l=1,int r=n){ if(l==r){ uppoint(rt,l); return; } build(ls,l,mid);build(rs,mid+1,r); up(rt); } void update(int pos,int x,int rt=1,int l=1,int r=n){ if(l==r){ c[l]+=x; uppoint(rt,l); return; } if(pos<=mid) update(pos,x,ls,l,mid); if(pos>mid) update(pos,x,rs,mid+1,r); up(rt); } int q(int ql,int qr,int op,int rt=1,int l=1,int r=n){ if(ql<=l&&r<=qr){ if(op==0) return t[rt].zero; if(op==1) return t[rt].posi; if(op==-1) return t[rt].neg; } int ans=0; if(ql<=mid) ans+=q(ql,qr,op,ls,l,mid); if(qr>mid) ans+=q(ql,qr,op,rs,mid+1,r); return ans; } void check(int x,int y){ if(x==y) cout<<"1"<<"\n"; else cout<<"0"<<"\n"; } signed main(){ n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) c[i]=a[i]-a[i-1]; build(1,1,n); int Q=read(); while(Q--){ int op;op=read(); if(op==1){ int l,r,x; l=read(),r=read(),x=read(); update(l,x);update(r+1,-x); } if(op==2){ int l,r;l=read(),r=read(); if(l==r) { cout<<1<<"\n"; continue; } int num=q(l+1,r,0); check(num,r-l); } if(op==3){ int l,r;l=read(),r=read(); if(l==r) { cout<<1<<"\n"; continue; } int num=q(l+1,r,1); check(num,r-l); } if(op==4){ int l,r;l=read(),r=read(); if(l==r) { cout<<1<<"\n"; continue; } int num=q(l+1,r,-1); check(num,r-l); } if(op==5){ int l,r;l=read(),r=read(); int L=l+1,R=r,ans=-1; while(L<=R){ int Mid=(L+R)>>1; int len=Mid-l; if(q(l+1,Mid,1)==len){ ans=Mid; L=Mid+1; } else R=Mid-1; } if(ans==-1) { cout<<"0"<<"\n"; continue; } if(q(l+1,r,1)==r-l) { cout<<0<<"\n"; continue; } if(q(ans+1,r,-1)==r-(ans+1)+1){ cout<<1<<"\n"; } else cout<<0<<"\n"; } } return 0; }
1011
队友写的
#include<bits/stdc++.h> #define int long long #define u i #define r (i+1)%4 #define d (i+2)%4 #define l (i+3)%4 using namespace std; struct node{ int x,y; }a[4][4]; inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } int fx(char c){ if (c=='N') return 0; if (c=='E') return 1; if (c=='S') return 2; if (c=='W') return 3; } const int N=505; const int INF=1e9+505; const int dx[]={0,1,0,-1}; const int dy[]={1,0,-1,0}; const node Null={INF,INF}; int n; int tim[N],wall[4],num; bool isNull(node a){ return a.x==INF&&a.y==INF; } node mx(node a,node b,int k){ if (isNull(b)) return a; if (isNull(a)) return b; if (k==0) return a.y>b.y?a:b; if (k==1) return a.x>b.x?a:b; if (k==2) return a.y<b.y?a:b; if (k==3) return a.x<b.x?a:b; } int sol(node a,node b,int k){ if (isNull(a)) return -1; if (isNull(b)) return -1; if (k==0) return a.y-b.y; if (k==1) return a.x-b.x; if (k==2) return b.y-a.y; if (k==3) return b.x-a.x; } void test(){ return; for (int i=0;i<4;i++){ for (int j=0;j<4;j++) printf("a[%lld][%lld]=%lld %lld\n",i,j,a[i][j].x,a[i][j].y); printf("\n"); } } void add(int x,int y,int k){ for (int i=0;i<4;i++) a[i][k]=mx(a[i][k],{x,y},i); //test(); } void addtime(int x){ if (x<0) return; tim[++num]=x; } node go(node a,int k,int t){ if (a.x==INF&&a.y==INF) return Null; a.x+=dx[k]*t; a.y+=dy[k]*t; return a; } void pt(node a){ //printf("%lld %lld ",a.x,a.y); } int cal(int t){ node tmp[4]; for (int i=0;i<4;i++) tmp[i]=Null; for (int i=0;i<4;i++){ for (int j=0;j<4;j++){ tmp[i]=mx(tmp[i],go(a[i][j],j,t),i); //printf("tmp[%lld]=%lld %lld\n",i,tmp[i].x,tmp[i].y); //test(); /* if (t==1){ printf("i=%lld j=%lld ",i,j); pt(a[i][j]); pt(go(a[i][j],j,t)); printf("\n"); } */ } } int y=tmp[0].y-tmp[2].y; int x=tmp[1].x-tmp[3].x; //printf("t=%lld xi=%lld xa=%lld yi=%lld ya=%lld\n",t,tmp[3].x,tmp[1].x,tmp[2].y,tmp[0].y); return 2*(x+y); } void work(){ node tmp; for (int i=0;i<4;i++){ tmp=mx(a[i][l],a[i][r],i); if (isNull(tmp)) { int x=sol(a[i][u],a[i][d],d); //pt(a[i][u]); //pt(a[i][d]); //printf("i=%lld x=%lld\n",i,x); //test(); if (x==-1) continue; addtime(x/2); addtime((x+1)/2); continue; } addtime(sol(tmp,a[i][u],u)); addtime(sol(tmp,a[i][d],d)); } int res=cal(0); //cerr << "case1:" << res << endl; //cerr << "case2:" << num << endl; //cerr << "case3:" << tim[1] << endl; for (int i=1;i<=num;i++) res=min(res,cal(tim[i])); cout << res << endl; } signed main() { for (int i=0;i<4;i++) for (int j=0;j<4;j++) a[i][j]=Null; cin >> n; for (int i=1;i<=n;i++){ int x,y; char c; cin >> x >> y >> c; add(x,y,fx(c)); } work(); return 0; }
1008
首先证明了跳跃时一定是从x跳到x的超集,否则不如直接从1跳到x
那么对于当前dij扩展到的节点j,枚举它的超集,设x为j的超集中的某个元素,假设 x 没有被访问过,则从 j 跳到 x 一定是最优解
因为k*(x|y)这部分代价一样,但是最短路的部分当前是最优解(dij的特性,最早扩展完的点dis值越小)
实现是扩展的时候dfs搜一下
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5,LIM=20; int n,m,k,dis[N+5]; vector<pair<int,int> > ver[N+5]; priority_queue<pair<int,int> > q; bool vis[N+5],jm[N+5]; inline int read() { int x=0;bool f=1;char ch=getchar(); for(;ch<'0'||ch>'9';ch=getchar())f^=(ch=='-'); for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<1)+(x<<3)+(ch^48); return f?x:-x; } int jump(int x,int y){return k*(x|y);} void dfs(int x,int r) { for(int i=0,v,y;i<LIM;++i) { if(x&(1<<i)) continue; y=x^(1<<i); if(jm[y]||y>n) continue; v=k*y,jm[y]=1; if(dis[y]==-1||dis[y]>dis[r]+v) dis[y]=dis[r]+v,q.push(make_pair(-dis[y],y)); dfs(y,r); } } void dijkstra() { for(int i=1;i<=n;++i) dis[i]=-1; for(int i=1;i<=n;++i) vis[i]=0; for(int i=1;i<=n;++i) jm[i]=0; dis[1]=0,q.push(make_pair(0,1)); for(int x;q.size();) { x=q.top().second,q.pop(); if(vis[x]) continue; vis[x]=1; for(int i=0,lim=ver[x].size();i<lim;++i) { int y=ver[x][i].second,v=ver[x][i].first; if(dis[y]==-1||dis[y]>dis[x]+v) dis[y]=dis[x]+v,q.push(make_pair(-dis[y],y)); } dfs(x,x); } } void Kafka() { n=read(),m=read(),k=read(); for(int i=1;i<=n;++i) ver[i].clear(); for(int i=1;i<=m;++i) { int u=read(),v=read(),w=read(); if(w>jump(u,v)) w=jump(u,v); ver[u].push_back(make_pair(w,v)); ver[v].push_back(make_pair(w,u)); } for(int i=2;i<=n;++i) ver[1].push_back(make_pair(jump(1,i),i)),ver[i].push_back(make_pair(jump(1,i),1)); dijkstra(); for(int i=2;i<=n;++i) cout<<dis[i]<<(i==n?'\n':' '); } signed main() { for(int T=read();T--;) Kafka(); return 0; }