我在考試時就想到了正解,只不過打的太醜而超時了,具體緣由:我在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--; } }