我在考试时就想到了正解,只不过打的太丑而超时了,具体缘由:我在dfs时不断作着memset(bz,0,sizeof,bz);。。。而后GG;;;正解2.OvO 题目对取 Galo 的要求,即不能同时取一对祖先和子孙。咱们可 以在 DFS 序上 DP。对于选择取 Galo[i]的决策,即选择了 DFS 序上 i 号节点的子树所对应的区间。只要选择的区间不相交、不重复,则 是一个合法的取法。这样,题目就成了一个区间覆盖 DP 问题,复 杂度 O(n*k)。个人代码太丑就不放了,避免大家也超时/emoji😆c++
这道题特别水,考场就有一堆人切了,正解:你只要判断儿子和父亲的颜色是否相同若不一样则把儿子加入答案,最后看root是否为白色就好了spa
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int i,j,n,m,k,l,e[2000001][2],h[2000001],color[600001],x,y,ans[600001],num,tot,z[1000001]; void add(int u,int v) { e[++tot][0]=h[u]; e[tot][1]=v; h[u]=tot; } int main() { freopen("tree.in","r",stdin); freopen("tree.out","w",stdout); scanf("%d",&n);for(i=1;i<=n;i++) scanf("%d",&color[i]); for(i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y); } z[++z[0]]=1; while(z[0]>0) { x=z[z[0]]; for(i=h[x];i;i=e[i][0]) {z[++z[0]]=e[i][1];if(color[e[i][1]]!=color[x]) ans[++num]=e[i][1];} h[x]=0; if(x==z[z[0]]) z[0]--; } if(color[1]!=0) ans[++num]=1; sort(ans+1,ans+1+num); for(i=1;i<=num;i++) printf("%d ",ans[i]); return 0; }
注意打dfs的要打人工栈。。code
考试时只会50分的。。。对于第一个问题是能够很轻松地解决
用贪心的思想,就是按照端点来排序,能放在同一个就放在同一个集合里面。
对于第二个问题咱们发现ans=|(l+r)-x|*2; 就对于一个区间其实就是中间点与选的位置的差距的两倍;
知道这个后,咱们要求的不过是一堆中间点与你选的位置的差距的最小值而已。
咱们设f[i]表示在1~i所放的最少羊的个数,其中强制i必放。g[i]表示在f[i]下的最小距离;
首先咱们知道f[i]必定是单调递增的,并且 对于i咱们枚举一个j转移时,必须保证j~i中的全部区间不存在 j<l<=r<i;这样你就没法从f[j]+1---->f[i] 这种状况你就须要多拿几只羊出来了,这也是个小剪枝。。。
而后就是转移g了。显然咱们能够把中心点在[j,mid]的全用j羊解决,(mid,i]的用i羊解决,而后用一个前缀和,处理每个区间就好了,(就好比:[j,mid]中全部中心点的和减去i*[j,mid]中的个数。。。。剩下本身思考)而后就没了。。。。。。注意统计答案时还要计算最后一个羊以后中心点的答案blog
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=300002; struct nup {long long l,r;}a[N]; long long i,j,n,m,k,t,l,r,c[N],y1,z,x,y,num,z1,tot,kk,mi,b[N],f[N],g[N],ma,num1[N],qz1[N],ans,mii,maa,mx; bool cmp(nup x,nup y){return x.l<y.l;} bool cmp1(nup x,nup y){return x.r<y.r;} long long abss(long long x){return(x>0?x:-x);} long long max(long long a,long long b){return a>b?a:b;} long long min(long long a,long long b){return a<b?a:b;} inline long long read(){ long long x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } int main() { freopen("grass.in","r",stdin); freopen("grass.out","w",stdout); n=read();t=read();mi=987654321; for(i=1;i<=n;i++) a[i].l=read(),a[i].r=read(),c[a[i].r]--,mi=min(mi,a[i].l),b[i]=(a[i].l+a[i].r)/2; sort(b+1,b+1+n); sort(a+1,a+1+n,cmp); x=a[1].l;y=1; while(x<=a[n].r&&y<=n) { z=0;tot=0;y1=y; while(c[x]==0) x++; while(a[y].l<=x&&a[y].r>=x&&y<=n) { if((a[y].l+a[y].r-1)/2<x) tot++; else tot--; z=max(z,a[y].l),c[a[y].r]++,y++; } num++;x=a[y].l; } printf("%lld\n",num); if(t==1) { sort(a+1,a+1+n,cmp1); mi=mii=987654321000000;ma=maa=0; for(i=1;i<=n;i++) qz1[b[i]]+=b[i],mi=min(mi,b[i]),ma=max(ma,b[i]),num1[b[i]]++,mii=min(mii,a[i].l),maa=max(maa,a[i].r); for(i=1;i<=maa;i++) qz1[i]+=qz1[i-1],num1[i]+=num1[i-1],g[i]=-1; for(i=1;i<=maa;i++) { for(;x<=n&&a[x].r<i;x++)mx=max(mx,a[x].l); for(j=mx;j<i;j++) { if(f[i]==0||(f[j]+1<=f[i])) { int mid=(i+j)/2; if(f[j]+1<f[i]) g[i]=-1; f[i]=f[j]+1; if(f[i]!=1) { if(g[i]!=-1) g[i]=min(g[i],1LL*(g[j]+qz1[mid]-qz1[j-1]-(num1[mid]-num1[j-1])*j*1LL)+1LL*(1LL*i*(num1[i]-num1[mid])-(qz1[i]-qz1[mid]))); else g[i]=1LL*(g[j]+qz1[mid]-qz1[j-1]-(num1[mid]-num1[j-1])*j*1LL)+1LL*(1LL*i*(num1[i]-num1[mid])-(qz1[i]-qz1[mid])); } else { if(g[i]!=-1) g[i]=min(g[i],(i*num1[i]-qz1[i])); else g[i]=(i*num1[i]-qz1[i]); } } } } mi=0;ans=987654321000000; for(;x<=n;x++)mx=max(mx,a[x].l); for(int i=mx;i<=maa;i++) if(f[i]==num)ans=min(ans,g[i]+qz1[maa]-qz1[i-1]-(num1[maa]-num1[i-1])*i); printf("%lld",ans*2); } }
就推柿子。。排序
由于A范围很小,因此咱们就把A归类,一样数字的归为一类,好比A={1,1,1,3,4,4,5,}
咱们就能够处理x=1时,x=3时......图片
那么原来的式子就变成了
那么咱们考虑设g[i]=b[i]%x,即按照a[i]来分组,在设在k个数中有t个数的g要大于T%x.(这个用桶)
那么有:(T是你二分的答案,k是相同的个数,由于A相同但B不必定相同)
而后预处理出后面那两个东西就能够了。ip
#pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast","inline") #include<cstdio> #include<cstring> #include<algorithm> using namespace std; struct nup {int a,b,id,qz;}f[400001]; long long n,m,k,t,op,x,y,num,kk,zz[400001],tot,g[400001],mid,l,r,G[400001],F[2001][2001]; bool cmp(nup x,nup y){return(x.a==y.a?(x.b>y.b):x.a<y.a);} inline long long pd(long long T) { long long res=0,i=0; for(register int i=1;i<=502;++i) { res+=F[i][i]*(T/i)-G[i]; res+=-F[i][i]+F[i][T%i]; } return res; } inline long long read(){ long long x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int main() { freopen("calculate.in","r",stdin); freopen("calculate.out","w",stdout); scanf("%lld",&t); while(t>0) { n=read();m=read(); memset(G,0,sizeof G);memset(F,0,sizeof F); for(register int i=1;i<=n;++i) f[i].a=read(); for(register int i=1;i<=n;++i) f[i].b=read(); for(register int i=1;i<=n;++i) G[f[i].a]+=f[i].b/f[i].a,F[f[i].a][f[i].b%f[i].a]++; for(register int i=1;i<=502;++i) for(register int j=1;j<=i;++j) F[i][j]+=F[i][j-1]; for(register int i=1;i<=m;++i) { op=read(); if(op==1) { x=read();y=read(); G[f[x].a]-=f[x].b/f[x].a; for(register int j=f[x].b%f[x].a;j<=f[x].a;++j) F[f[x].a][j]--; f[x].a=y; G[f[x].a]+=f[x].b/f[x].a; for(register int j=f[x].b%f[x].a;j<=f[x].a;++j) F[f[x].a][j]++; } else if(op==2) { x=read();y=read(); G[f[x].a]+=y/f[x].a-f[x].b/f[x].a; long long l=f[x].b%f[x].a,r=y%f[x].a; if(l<=r) for(register int j=l;j<r;++j) F[f[x].a][j]--; else for(register int j=r;j<l;++j) F[f[x].a][j]++; f[x].b=y; } else { k=read(); l=1;r=f[1].a*k+f[1].b+f[2].b+f[2].a*k; while(l<r) { mid=(l+r)/2; long long cnt=pd(mid); if(cnt>=k) r=mid;else l=mid+1; } printf("%lld\n",l); } } t--; } }