The 2023 ICPC Asia Hong Kong Regional Programming Contest (AEFHKL)
在考试周打比赛就像在刀尖上跳舞,在赌桌上下筹码
我只希望专业课它别挂
不然搞钱吃饭就麻烦了
====================
学弟写的,阅读理解题,读对了就是简单树dp
#include<bits/stdc++.h> using namespace std; const int N=2e5; int n,f[N+5]; vector<int> e[N+5]; void dfs(int x) { int Mx1=0,Mx2=0; for(int i=0,lim=e[x].size();i<lim;++i) { int y=e[x][i]; dfs(y); if(f[y]>=Mx1) Mx2=Mx1,Mx1=f[y]; else if(f[y]>Mx2) Mx2=f[y]; } f[x]=max(Mx1,Mx2+1); } void Kafka() { cin>>n; for(int i=1;i<=n;++i) { int tmp; cin>>tmp; if(tmp) e[tmp].push_back(i); } dfs(1); cout<<f[1]<<endl; for(int i=1;i<=n;++i) e[i].clear(); } signed main() { int T; cin>>T; while(T--) Kafka(); return 0; } /* 4 3 0 1 2 7 0 1 2 2 1 4 1 3 0 1 2 7 0 1 2 2 1 4 1 */
发现可以固定右端点->
在右端点往右移动的过程中其实影响的只有一个数,撤销掉之前的操作,再补上新的即可
(显然一个数对答案的影响是一段连续区间)
转化成数据结构,区间加法,求区间内有多少为0的个数
线段树可以做,除了常规区间操作外加一个维护最小值和最小值个数,显然0的个数==最小值为0时最小值的个数
#include<bits/stdc++.h> using namespace std; const int maxn=1e6+5; int cnt=0,n,k; vector<int>v[maxn]; #define ls (rt<<1) #define rs (rt<<1|1) #define mid ((l+r)>>1) // 区间加 struct seg_tree{ int mi,micnt;// 区间最小值 最小值个数 int cnt0;// 区间为0的个数和 int lazy;// lazy tag }t[maxn<<2]; void dowwn(int rt,int val){ t[rt].mi+=val; if(t[rt].mi==0) t[rt].cnt0=t[rt].micnt; else t[rt].cnt0=0; t[rt].lazy+=val; } void down(int rt){ if(!t[rt].lazy) return ; dowwn(ls,t[rt].lazy); dowwn(rs,t[rt].lazy); t[rt].lazy=0; } void up(int rt){ int tmp=min(t[ls].mi,t[rs].mi); t[rt].mi=tmp; t[rt].micnt=0; if(t[ls].mi==tmp) t[rt].micnt+=t[ls].micnt; if(t[rs].mi==tmp) t[rt].micnt+=t[rs].micnt; if(t[rt].mi==0) t[rt].cnt0=t[rt].micnt; else t[rt].cnt0=0; //cout<<rt<<" rt "<<t[rt].mi<<" "<<t[rt].micnt<<endl; } void update(int ql,int qr,int val,int rt=1,int l=1,int r=n){ // cout<<ql<<" "<<qr<<" "<<l<<" "<<r<<endl; if(l>=ql&&r<=qr){ dowwn(rt,val); return ; } down(rt); if(ql<=mid) update(ql,qr,val,ls,l,mid); if(qr>mid) update(ql,qr,val,rs,mid+1,r); up(rt); } int query(int ql,int qr,int rt=1,int l=1,int r=n){ if(l>=ql&&r<=qr){ return t[rt].cnt0; } down(rt); int ans=0; if(ql<=mid) ans+=query(ql,qr,ls,l,mid); if(qr>mid) ans+=query(ql,qr,rs,mid+1,r); up(rt); return ans; } void build(int rt=1,int l=1,int r=n){ t[rt].mi=0; t[rt].micnt=r-l+1; t[rt].cnt0=r-l+1; t[rt].lazy=0; if(l==r) { return; } build(ls,l,mid); build(rs,mid+1,r); } int vis[maxn],p[maxn],sz[maxn],a[maxn]; int main(){ ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>k; for(int i=1;i<=n;i++){ int x; cin>>x; if(!vis[x]){ vis[x]=++cnt; p[cnt]=1;// 指向0 v[cnt].push_back(-1); v[cnt].push_back(i); sz[cnt]=1; } else { sz[vis[x]]++; v[vis[x]].push_back(i); } a[i]=x; } build(); long long tot=0; for(int i=1;i<=cnt;i++){ int l=p[i]+k-1; if(l<=sz[i]) { int r; if(l==sz[i]) r=n; else r=v[i][l+1]-1; // cout<<v[i][l]<<" ??"<<r<<endl; update(v[i][l],r,1); } } // cout<<query(1,n)<<endl; tot+=query(1,n); for(int i=2;i<=n;i++){ int id=vis[a[i-1]]; int l=p[id]+k-1,r; // cout<<i<<" :"<<endl; if(l<=sz[id]) { // cout<<l<<" "<<sz[id]<<" "<<v[id][l+1]-1<<endl; if(l==sz[id]) r=n; else r=v[id][l+1]-1; // cout<<v[id][l]<<" "<<r<<endl; update(v[id][l],r,-1); } p[id]++; l=p[id]+k-1; if(l<=sz[id]) { if(l==sz[id]) r=n; else r=v[id][l+1]-1; update(v[id][l],r,1); } //cout<<i<<" #"<<6<<endl; // cout<<"ans: "<<i<<" "<<query(i,n)<<endl; tot+=query(i,n); } cout<<tot<<endl; }
最开始贪心的想法是每段均分,然后有的多一,暴力dfs
但其实有问题,记上一段的长度为x,第i段的范围应该为[x-1,x+1](当然要判下能否取到
然后就是高精的问题,用acwing vector的模板t掉了,换成手写数组
那场的金牌题,vp时开了来不及写,赛后补的,交了20发,最开始有点想当然了,写得不用心
#include<bits/stdc++.h> using namespace std; int n,k,avg; int ans[20]; string s; int a[10][(int)2e5+10]; int sum[(int)2e5+10]; int out[(int)2e5+10],l=0; void dfs(int step,int tot){ // cout<<step<<" "<<tot<<endl; if(step==k+2){ if(tot!=0) return; int last=n-1,len=0; for(int i=1;i<=k+1;i++) len=max(len,ans[i]); for(int i=1;i<=len+5;i++)sum[i]=0; for(int i=1;i<=k+1;i++){ for(int j=1;j<=ans[i];j++){ a[i][j]=(s[last]-'0'); last--; } for(int j=ans[i]+1;j<=len+5;j++) a[i][j]=0; } for(int i=1;i<=len+2;i++) { sum[i]=0; for(int j=1;j<=k+1;j++){ sum[i]+=a[j][i]; } } for(int i=1;i<=len;i++) { int d=sum[i]/10; sum[i]%=10; sum[i+1]+=d; } if(sum[len+1]) len++; if(sum[len]>=10) { len++; sum[len]+=sum[len-1]/10; sum[len-1]%=10; } if(sum[len]>=10) { len++; sum[len]+=sum[len-1]/10; sum[len-1]%=10; } if(len<l){ l=len; for(int i=1;i<=len;i++) out[i]=sum[i]; } else if(l==len){ int flag=1; for(int i=l;i>=1;i--){ if(sum[i]!=out[i]){ if(sum[i]>out[i]) {} else flag=0; } if(sum[i]!=out[i]) break; } if(flag==0){ for(int i=1;i<=len;i++) out[i]=sum[i]; } } return ; } if(step!=1){ for(int i=max(1,ans[step-1]-1);i<=min(tot,ans[step-1]+1);i++){ if(tot>=i){ ans[step]=i; dfs(step+1,tot-i); } } } else { ans[step]=avg-1; dfs(step+1,tot-(avg-1)); ans[step]=avg; dfs(step+1,tot-avg); ans[step]=avg+1; dfs(step+1,tot-(avg+1)); ans[step]=avg+2; dfs(step+1,tot-(avg+2)); } } void solve(){ cin>>n>>k; cin>>s; l=2e5+3; avg=n/(k+1); dfs(1,n); for(int i=l;i>=1;i--) cout<<out[i]; cout<<endl; } int main(){ ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); // freopen("lys.in","r",stdin); int t; cin>>t; while(t--){ solve(); } }
H.Another Goose Goose Duck Problem
签到,好像是个简单数学,没看,直接丢该队友了
#include<bits/stdc++.h> using namespace std; int l,r,b,k; int ans; signed main() { cin>>l>>r>>b>>k; if(l<=b) ans=b; else if(l%b==0) ans=l; else ans=(l/b+1)*b; cout<<1LL*ans*k<<endl; return 0; }
签到,数学,没看,学弟写的
#include<bits/stdc++.h> using namespace std; const int N=1e5; int n,a[N+5],Min; signed main() { Min=2e9; cin>>n; for(int i=1;i<=n;++i) { cin>>a[i]; Min=min(Min,a[i]); } int ans=-1; for(int i=1;i<=n;++i) { if(a[i]==Min||a[i]>=Min*2) continue; ans=0; } ans=ans?Min:Min/2; cout<<max(1,ans)<<endl; return 0; }
首先n>m+k无解
其次如果出现的先后顺序不一样也无解(这个一直没有考虑到,做的不好
然后是判断有无解:
显然删除的顺序会影响到答案,从最大的数开始删最优
对于某数x,它合法的删除范围为(左边第一个大于它的数,右边第一个大于它的数)
预处理出每个数的合法删除范围(写个线段树上二分),然后跟手上有的操作数排完序跑双指针
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+5; int n,m,k,a[maxn],b[maxn],l[maxn],vis[maxn],need[maxn],to[maxn]; #define ls (rt<<1) #define rs (rt<<1|1) #define mid ((l+r)>>1) struct seg_tree{ int mx,real_len; int l,r; }t[maxn<<2]; void up(int rt){ t[rt].real_len=t[ls].real_len+t[rs].real_len; t[rt].mx=max(t[ls].mx,t[rs].mx); } void build(int rt=1,int l=1,int r=n){ t[rt].l=l,t[rt].r=r; t[rt].real_len=r-l+1; if(l==r) { t[rt].mx=a[l]; return; } build(ls,l,mid);build(rs,mid+1,r); up(rt); } void del(int pos,int rt=1,int l=1,int r=n){ if(l==r){ t[rt].mx=-2333; t[rt].real_len=0; return; } if(pos<=mid) del(pos,ls,l,mid); else del(pos,rs,mid+1,r); up(rt); } int query(int ql,int qr,int rt=1,int l=1,int r=n){ if(l>=ql&&r<=qr){ return t[rt].mx; } int ans=-2333; if(ql<=mid) ans=max(ans,query(ql,qr,ls,l,mid)); if(qr>mid) ans=max(ans,query(ql,qr,rs,mid+1,r)); up(rt); return ans; } const int INF=1e9+7; int ask_R(int ql,int qr,int val,int rt=1,int l=1,int r=n){ if(ql>qr) return INF; if(l==r){ return t[rt].mx>=val ? l : INF; } int res=INF; if(ql<=mid){ if(t[ls].mx>=val) res=ask_R(ql,qr,val,ls,l,mid); if(res==INF&&t[rs].mx>=val) res=ask_R(ql,qr,val,rs,mid+1,r); } else if(t[rs].mx>=val){ res=ask_R(ql,qr,val,rs,mid+1,r); } return res; } int ask_L(int ql,int qr,int val,int rt=1,int l=1,int r=n){ if(ql>qr) return INF; if(l==r){ return t[rt].mx>=val ? l : INF; } int res=INF; if(qr>mid){ if(t[rs].mx>=val) res=ask_L(ql,qr,val,rs,mid+1,r); if(res==INF&&t[ls].mx>=val) res=ask_L(ql,qr,val,ls,l,mid); } else if(t[ls].mx>=val){ res=ask_L(ql,qr,val,ls,l,mid); } return res; } int askNum(int ql,int qr,int rt=1,int l=1,int r=n){ if(ql>qr) return 0; if(l>=ql&&r<=qr){ return t[rt].real_len; } int ans=0; if(ql<=mid) ans+=askNum(ql,qr,ls,l,mid); if(qr>mid) ans+=askNum(ql,qr,rs,mid+1,r); up(rt); return ans; } struct node{ int pos,val; }q[maxn]; bool cmp(node a,node b){ return a.val>b.val; } bool mycmp(int a,int b){ return a>b; } void solve(){ cin>>n>>m>>k; for(int i=1;i<=n;i++) vis[i]=0; for(int i=1;i<=n;i++) { cin>>a[i]; to[a[i]]=i; } for(int i=1;i<=m;i++) { cin>>b[i]; vis[b[i]]=1; } for(int i=1;i<=k;i++) { cin>>l[i]; } if(n>m+k) { cout<<"NO"<<endl; return ; } for(int i=1;i<m;i++){ if(to[b[i]]>to[b[i+1]]) { cout<<"NO"<<endl; return; } } build(); int cnt=0; for(int i=1;i<=n;i++){ if(!vis[a[i]]){ // need to be delet cnt++; q[cnt].pos=i,q[cnt].val=a[i]; } } sort(q+1,q+1+cnt,cmp); for(int i=1;i<=cnt;i++){ int len=0; int ans; // cout<<q[i].pos<<" # "<<endl; ans=ask_R(q[i].pos+1,n,q[i].val); // cout<<"R: "<<ans<<endl; if(ans==INF) ans=n; else ans--; len+=askNum(q[i].pos,ans); ans=ask_L(1,q[i].pos-1,q[i].val); // cout<<"L: "<<ans<<endl; if(ans==INF) ans=1; else ans++; len+=askNum(ans,q[i].pos); len--; // cout<<"len: "<<len<<endl; del(q[i].pos); need[i]=len; } sort(need+1,need+cnt+1,mycmp); sort(l+1,l+k+1,mycmp); int p=1,flag=1; l[k+1]=0; for(int i=1;i<=cnt;i++){ while(l[p]>need[i]) p++; if(p==k+1) { flag=0;break; } else p++; } if(flag) cout<<"YES"<<endl; else cout<<"NO"<<endl; } int main(){ ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); //freopen("lys.in","r",stdin); int t; cin>>t; while(t--){ solve(); } }